first commit of code
parent
7d2963ce30
commit
f16f85fd92
|
@ -0,0 +1,826 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "cel.h"
|
||||
#include "cpgplot.h"
|
||||
#include "qfits.h"
|
||||
#include <gsl/gsl_multifit.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#define NMAX 2048
|
||||
#define LIM 128
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
|
||||
struct image {
|
||||
int naxis1,naxis2,nframes;
|
||||
float *zavg,*zstd,*zmax,*znum;
|
||||
double ra0,de0;
|
||||
float x0,y0;
|
||||
float a[2],b[2];
|
||||
double mjd;
|
||||
float *dt;
|
||||
};
|
||||
struct transformation {
|
||||
double mjd;
|
||||
double ra0,de0;
|
||||
float a[3],b[3];
|
||||
float x0,y0;
|
||||
float xrms,yrms,rms;
|
||||
};
|
||||
struct star {
|
||||
double ra,de;
|
||||
float pmra,pmde;
|
||||
float mag;
|
||||
};
|
||||
struct catalog {
|
||||
int n;
|
||||
float x[NMAX],y[NMAX],imag[NMAX],fm[NMAX],fb[NMAX],bg[NMAX];
|
||||
double ra[NMAX],de[NMAX],vmag[NMAX];
|
||||
double rx[NMAX],ry[NMAX];
|
||||
float xres[NMAX],yres[NMAX],res[NMAX];
|
||||
int usage[NMAX];
|
||||
};
|
||||
struct image read_fits(char *filename);
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y);
|
||||
void reverse(double ra0,double de0,double x,double y,double *ra,double *de);
|
||||
double gmst(double mjd);
|
||||
double modulo(double x,double y);
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
struct catalog match_catalogs(char *pixcat,char *astcat,struct transformation t,struct image img,float rmax,float mmin);
|
||||
void plot_astrometric_catalog(struct transformation t,struct image img,float mmin);
|
||||
void plot_pixel_catalog(char *filename);
|
||||
void lfit2d(float *x,float *y,float *z,int n,float *a);
|
||||
void add_fits_keywords(struct transformation t,char *filename);
|
||||
void modify_fits_keywords(struct transformation t,char *filename);
|
||||
|
||||
void plot_image(struct image img,struct transformation t,struct catalog c,char *filename,float mmin)
|
||||
{
|
||||
int i;
|
||||
float tr[]={-0.5,1.0,0.0,-0.5,0.0,1.0};
|
||||
float heat_l[]={0.0,0.2,0.4,0.6,1.0};
|
||||
float heat_r[]={0.0,0.5,1.0,1.0,1.0};
|
||||
float heat_g[]={0.0,0.0,0.5,1.0,1.0};
|
||||
float heat_b[]={0.0,0.0,0.0,0.3,1.0};
|
||||
float zmin,zmax,zavg,zstd;
|
||||
|
||||
for (i=0,zavg=0.0;i<img.naxis1*img.naxis2;i++)
|
||||
zavg+=img.zmax[i];
|
||||
zavg/=(float) img.naxis1*img.naxis2;
|
||||
for (i=0,zstd=0.0;i<img.naxis1*img.naxis2;i++)
|
||||
zstd+=pow(img.zavg[i]-zavg,2);
|
||||
zstd=sqrt(zstd/(float) (img.naxis1*img.naxis2));
|
||||
zmin=zavg-2*zstd;
|
||||
zmax=zavg+6*zstd;
|
||||
|
||||
cpgopen("1/xs");
|
||||
cpgwnad(0.0,img.naxis1,0.0,img.naxis2);
|
||||
cpgctab (heat_l,heat_r,heat_g,heat_b,5,1.0,0.5);
|
||||
|
||||
cpgimag(img.zavg,img.naxis1,img.naxis2,1,img.naxis1,1,img.naxis2,zmin,zmax,tr);
|
||||
cpgbox("BCTSNI",0.,0,"BCTSNI",0.,0);
|
||||
|
||||
cpgsci(3);
|
||||
plot_pixel_catalog(filename);
|
||||
|
||||
cpgsci(4);
|
||||
plot_astrometric_catalog(t,img,mmin);
|
||||
cpgsci(2);
|
||||
for (i=0;i<c.n;i++)
|
||||
cpgpt1(c.x[i]+t.x0,c.y[i]+t.y0,24);
|
||||
|
||||
cpgend();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void usage(float mmin,float rmin)
|
||||
{
|
||||
printf("addwcs: Add/fit World Coordinate System to a FITS file\n\n");
|
||||
|
||||
printf("-f <file>: FITS file to add/fit WCS to [required]\n");
|
||||
printf("-r <file>: FITS file with reference WCS [required]\n");
|
||||
printf("-m <float>: Magnitude cut-off in Tycho-2 catalog [optional; default %.1f]\n",mmin);
|
||||
printf("-R <float>: Radius cut-off for matching [optional; default %.1f pix]\n",rmin);
|
||||
printf("-p Plot image and selected stars [optional]\n");
|
||||
printf("-a Add WCS keywords to input file (instead of modify) [optional]\n");
|
||||
printf("-t Track on a fixed RA/Dec (correct for field rotation)\n");
|
||||
printf("-h Print this help\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get reference transformation
|
||||
struct transformation reference(char *filename)
|
||||
{
|
||||
struct transformation t;
|
||||
|
||||
t.mjd=atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
t.ra0=atof(qfits_query_hdr(filename,"CRVAL1"));
|
||||
t.de0=atof(qfits_query_hdr(filename,"CRVAL2"));
|
||||
t.x0=atof(qfits_query_hdr(filename,"CRPIX1"));
|
||||
t.y0=atof(qfits_query_hdr(filename,"CRPIX2"));
|
||||
t.a[0]=0.0;
|
||||
t.a[1]=3600.0*atof(qfits_query_hdr(filename,"CD1_1"));
|
||||
t.a[2]=3600.0*atof(qfits_query_hdr(filename,"CD1_2"));
|
||||
t.b[0]=0.0;
|
||||
t.b[1]=3600.0*atof(qfits_query_hdr(filename,"CD2_1"));
|
||||
t.b[2]=3600.0*atof(qfits_query_hdr(filename,"CD2_2"));
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void rotate(float theta,float *x,float *y)
|
||||
{
|
||||
float ct,st;
|
||||
float x0,y0;
|
||||
|
||||
ct=cos(theta*D2R);
|
||||
st=sin(theta*D2R);
|
||||
x0= *x;
|
||||
y0= *y;
|
||||
|
||||
*x=ct*x0-st*y0;
|
||||
*y=st*x0+ct*y0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
struct transformation t;
|
||||
struct image img;
|
||||
char *fitsfile=NULL,*reffile=NULL,catfile[128],calfile[128];
|
||||
FILE *outfile;
|
||||
struct catalog c;
|
||||
float mmin=10.0,rmin=10.0;
|
||||
double ra0,de0;
|
||||
float q0,q1;
|
||||
float rmsmin;
|
||||
float x[NMAX],y[NMAX],rx[NMAX],ry[NMAX];
|
||||
int arg=0,plot=0,add=0,track=0;
|
||||
char *env,starfile[128];
|
||||
|
||||
// Environment variables
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(starfile,"%s/data/tycho2.dat",env);
|
||||
|
||||
// Decode options
|
||||
if (argc>1) {
|
||||
while ((arg=getopt(argc,argv,"f:r:m:R:hpnta"))!=-1) {
|
||||
switch (arg) {
|
||||
|
||||
case 'f':
|
||||
fitsfile=optarg;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
reffile=optarg;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
mmin=atof(optarg);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
track=1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
rmin=atof(optarg);
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
plot=1;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
add=1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(mmin,rmin);
|
||||
return 0;
|
||||
|
||||
default:
|
||||
usage(mmin,rmin);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
usage(mmin,rmin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check if minimum input is provided
|
||||
if (fitsfile==NULL || reffile==NULL) {
|
||||
usage(mmin,rmin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check this is indeed a FITS file
|
||||
if (is_fits_file(fitsfile)!=1) {
|
||||
printf("%s is not a FITS file\n",fitsfile);
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
// Check this is indeed a FITS file
|
||||
if (is_fits_file(reffile)!=1) {
|
||||
printf("%s is not a FITS file\n",reffile);
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
// Read fits file
|
||||
img=read_fits(fitsfile);
|
||||
sprintf(catfile,"%s.cat",fitsfile);
|
||||
sprintf(calfile,"%s.cal",fitsfile);
|
||||
|
||||
// Read reference transformation
|
||||
t=reference(reffile);
|
||||
|
||||
// Correct astrometry for fixed or tracked setup
|
||||
if (track==0)
|
||||
t.ra0=modulo(t.ra0+gmst(img.mjd)-gmst(t.mjd),360.0);
|
||||
|
||||
// Match catalog
|
||||
c=match_catalogs(catfile,starfile,t,img,rmin,mmin);
|
||||
|
||||
|
||||
// Plot
|
||||
if (plot==1)
|
||||
plot_image(img,t,c,catfile,mmin);
|
||||
|
||||
// Do fit
|
||||
for (l=0;l<10;l++) {
|
||||
for (j=0;j<5;j++) {
|
||||
// Transform
|
||||
for (i=0;i<c.n;i++)
|
||||
forward(t.ra0,t.de0,c.ra[i],c.de[i],&c.rx[i],&c.ry[i]);
|
||||
|
||||
// Select
|
||||
for (i=0,k=0;i<c.n;i++) {
|
||||
if (c.usage[i]==1) {
|
||||
x[k]=c.x[i];
|
||||
y[k]=c.y[i];
|
||||
rx[k]=(float) c.rx[i];
|
||||
ry[k]=(float) c.ry[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
// Fit
|
||||
lfit2d(x,y,rx,k,t.a);
|
||||
lfit2d(x,y,ry,k,t.b);
|
||||
|
||||
// Move reference point
|
||||
reverse(t.ra0,t.de0,t.a[0],t.b[0],&ra0,&de0);
|
||||
t.ra0=ra0;
|
||||
t.de0=de0;
|
||||
}
|
||||
|
||||
// Compute and plot residuals
|
||||
for (i=0,t.xrms=0.0,t.yrms=0.0,m=0;i<c.n;i++) {
|
||||
if (c.usage[i]==1) {
|
||||
c.xres[i]=c.rx[i]-(t.a[0]+t.a[1]*c.x[i]+t.a[2]*c.y[i]);
|
||||
c.yres[i]=c.ry[i]-(t.b[0]+t.b[1]*c.x[i]+t.b[2]*c.y[i]);
|
||||
|
||||
c.res[i]=sqrt(c.xres[i]*c.xres[i]+c.yres[i]*c.yres[i]);
|
||||
t.xrms+=c.xres[i]*c.xres[i];
|
||||
t.yrms+=c.yres[i]*c.yres[i];
|
||||
t.rms+=c.xres[i]*c.xres[i]+c.yres[i]*c.yres[i];
|
||||
m++;
|
||||
}
|
||||
}
|
||||
t.xrms=sqrt(t.xrms/(float) m);
|
||||
t.yrms=sqrt(t.yrms/(float) m);
|
||||
t.rms=sqrt(t.rms/(float) m);
|
||||
|
||||
// Deselect outliers
|
||||
for (i=0;i<c.n;i++) {
|
||||
if (c.res[i]>2*t.rms)
|
||||
c.usage[i]=0;
|
||||
}
|
||||
}
|
||||
|
||||
// Print results
|
||||
outfile=fopen(calfile,"w");
|
||||
for (i=0;i<c.n;i++)
|
||||
if (c.usage[i]==1)
|
||||
fprintf(outfile,"%10.4f %10.4f %10.6f %10.6f %8.3f %8.3f %8.3f %8.3f %8.3f\n",c.x[i],c.y[i],c.ra[i],c.de[i],c.vmag[i],c.imag[i],c.fb[i],c.fm[i],c.bg[i]);
|
||||
fclose(outfile);
|
||||
|
||||
printf("%s %8.4lf %8.4lf ",fitsfile,t.ra0,t.de0);
|
||||
printf("%3d/%3d %6.1f %6.1f %6.1f\n",m,c.n,t.xrms,t.yrms,t.rms);
|
||||
|
||||
// Add keywords
|
||||
if (add==1)
|
||||
add_fits_keywords(t,fitsfile);
|
||||
else
|
||||
modify_fits_keywords(t,fitsfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read fits image
|
||||
struct image read_fits(char *filename)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
struct image img;
|
||||
|
||||
// Image size
|
||||
img.naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
img.naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
|
||||
// MJD
|
||||
img.mjd=(double) atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
|
||||
// Number of frames
|
||||
img.nframes=atoi(qfits_query_hdr(filename,"NFRAMES"));
|
||||
|
||||
// Timestamps
|
||||
img.dt=(float *) malloc(sizeof(float)*img.nframes);
|
||||
for (i=0;i<img.nframes;i++) {
|
||||
sprintf(key,"DT%04d",i);
|
||||
strcpy(val,qfits_query_hdr(filename,key));
|
||||
sscanf(val+1,"%f",&img.dt[i]);
|
||||
// img.dt[i]=atof(qfits_query_hdr(filename,key));
|
||||
}
|
||||
|
||||
// Allocate image memory
|
||||
img.zavg=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.zstd=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.zmax=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.znum=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
|
||||
// Set parameters
|
||||
ql.xtnum=0;
|
||||
ql.ptype=PTYPE_FLOAT;
|
||||
ql.filename=filename;
|
||||
|
||||
// Loop over planes
|
||||
for (k=0;k<4;k++) {
|
||||
ql.pnum=k;;
|
||||
|
||||
// Initialize load
|
||||
if (qfitsloader_init(&ql) != 0)
|
||||
printf("Error initializing data loading\n");
|
||||
|
||||
// Test load
|
||||
if (qfits_loadpix(&ql) != 0)
|
||||
printf("Error loading actual data\n");
|
||||
|
||||
// Fill z array
|
||||
for (i=0,l=0;i<img.naxis1;i++) {
|
||||
for (j=0;j<img.naxis2;j++) {
|
||||
if (k==0) img.zavg[l]=ql.fbuf[l];
|
||||
if (k==1) img.zstd[l]=ql.fbuf[l];
|
||||
if (k==2) img.zmax[l]=ql.fbuf[l];
|
||||
if (k==3) img.znum[l]=ql.fbuf[l];
|
||||
l++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
// Get a x and y from a RA and Decl
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="TAN";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celfwd(pcode,ra,de,&cel,&phi,&theta,&prj,x,y)) {
|
||||
printf("Error in Projection (celfwd)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
*x*=3600.;
|
||||
*y*=3600.;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double gmst(double mjd)
|
||||
{
|
||||
double t,gmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
gmst=modulo(280.46061837+360.98564736629*(mjd-51544.5)+t*t*(0.000387933-t/38710000),360.0);
|
||||
|
||||
return gmst;
|
||||
}
|
||||
|
||||
// Return x modulo y [0,y)
|
||||
double modulo(double x,double y)
|
||||
{
|
||||
x=fmod(x,y);
|
||||
if (x<0.0) x+=y;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
// Match catalogs
|
||||
struct catalog match_catalogs(char *pixcat,char *astcat,struct transformation t,struct image img,float rmax,float mmin)
|
||||
{
|
||||
int i=0,imin,j,k,np;
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
struct star s;
|
||||
double rx,ry,d,dx,dy;
|
||||
int usage[NMAX];
|
||||
float xp[NMAX],yp[NMAX],mp[NMAX],x,y,fb[NMAX],fm[NMAX],bg[NMAX];
|
||||
struct catalog c;
|
||||
float r,rmin;
|
||||
|
||||
// Read pixel catalog
|
||||
file=fopen(pixcat,"r");
|
||||
if (file==NULL) {
|
||||
printf("pixel catalog not found\n");
|
||||
exit(-1);
|
||||
}
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
sscanf(line,"%f %f %f %f %f %f",&xp[i],&yp[i],&mp[i],&fb[i],&fm[i],&bg[i]);
|
||||
usage[i]=1;
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
np=i;
|
||||
|
||||
// Denominator
|
||||
d=t.a[1]*t.b[2]-t.a[2]*t.b[1];
|
||||
|
||||
// Read astrometric catalog
|
||||
file=fopen(astcat,"rb");
|
||||
if (file==NULL) {
|
||||
printf("astrometric catalog not found\n");
|
||||
exit(-1);
|
||||
}
|
||||
j=0;
|
||||
while (!feof(file)) {
|
||||
fread(&s,sizeof(struct star),1,file);
|
||||
if (s.mag>mmin)
|
||||
continue;
|
||||
r=acos(sin(t.de0*D2R)*sin(s.de*D2R)+cos(t.de0*D2R)*cos(s.de*D2R)*cos((t.ra0-s.ra)*D2R))*R2D;
|
||||
if (r>90.0)
|
||||
continue;
|
||||
forward(t.ra0,t.de0,s.ra,s.de,&rx,&ry);
|
||||
|
||||
dx=rx-t.a[0];
|
||||
dy=ry-t.b[0];
|
||||
x=(t.b[2]*dx-t.a[2]*dy)/d+t.x0;
|
||||
y=(t.a[1]*dy-t.b[1]*dx)/d+t.y0;
|
||||
|
||||
// On image
|
||||
if (x>0.0 && x<img.naxis1 && y>0.0 && y<img.naxis2) {
|
||||
// Loop over pixel catalog
|
||||
for (i=0;i<np;i++) {
|
||||
r=sqrt(pow(xp[i]-x,2)+pow(yp[i]-y,2));
|
||||
if (i==0 || r<rmin) {
|
||||
rmin=r;
|
||||
imin=i;
|
||||
}
|
||||
}
|
||||
|
||||
// Select
|
||||
if (rmin<rmax && usage[imin]==1) {
|
||||
c.x[j]=xp[imin]-t.x0;
|
||||
c.y[j]=yp[imin]-t.y0;
|
||||
c.imag[j]=mp[imin];
|
||||
c.fb[j]=fb[imin];
|
||||
c.fm[j]=fm[imin];
|
||||
c.bg[j]=bg[imin];
|
||||
c.ra[j]=s.ra;
|
||||
c.de[j]=s.de;
|
||||
c.vmag[j]=s.mag;
|
||||
c.usage[j]=1;
|
||||
usage[imin]=0;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
c.n=j;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Plot astrometric catalog
|
||||
void plot_astrometric_catalog(struct transformation t,struct image img,float mmin)
|
||||
{
|
||||
int i=0;
|
||||
FILE *file;
|
||||
struct star s;
|
||||
double rx,ry,d,r;
|
||||
double ra,de;
|
||||
float x,y;
|
||||
char *env,starfile[128];
|
||||
|
||||
// Environment variables
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(starfile,"%s/data/tycho2.dat",env);
|
||||
|
||||
d=t.a[1]*t.b[2]-t.a[2]*t.b[1];
|
||||
|
||||
file=fopen(starfile,"rb");
|
||||
while (!feof(file)) {
|
||||
fread(&s,sizeof(struct star),1,file);
|
||||
if (s.mag>mmin)
|
||||
continue;
|
||||
r=acos(sin(t.de0*D2R)*sin(s.de*D2R)+cos(t.de0*D2R)*cos(s.de*D2R)*cos((t.ra0-s.ra)*D2R))*R2D;
|
||||
if (r>90.0)
|
||||
continue;
|
||||
forward(t.ra0,t.de0,s.ra,s.de,&rx,&ry);
|
||||
x=(t.b[2]*rx-t.a[2]*ry)/d+t.x0;
|
||||
y=(t.a[1]*ry-t.b[1]*rx)/d+t.y0;
|
||||
if (x>0.0 && x<img.naxis1 && y>0.0 && y<img.naxis2)
|
||||
cpgpt1(x,y,24);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Plot pixel catalog
|
||||
void plot_pixel_catalog(char *filename)
|
||||
{
|
||||
int i=0;
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
float x,y,mag;
|
||||
|
||||
// Read catalog
|
||||
file=fopen(filename,"r");
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
sscanf(line,"%f %f %f",&x,&y,&mag);
|
||||
|
||||
cpgpt1(x,y,4);
|
||||
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Linear 2D fit
|
||||
void lfit2d(float *x,float *y,float *z,int n,float *a)
|
||||
{
|
||||
int i,j,m;
|
||||
double chisq;
|
||||
gsl_matrix *X,*cov;
|
||||
gsl_vector *yy,*w,*c;
|
||||
|
||||
X=gsl_matrix_alloc(n,3);
|
||||
yy=gsl_vector_alloc(n);
|
||||
w=gsl_vector_alloc(n);
|
||||
|
||||
c=gsl_vector_alloc(3);
|
||||
cov=gsl_matrix_alloc(3,3);
|
||||
|
||||
// Fill matrices
|
||||
for(i=0;i<n;i++) {
|
||||
gsl_matrix_set(X,i,0,1.0);
|
||||
gsl_matrix_set(X,i,1,x[i]);
|
||||
gsl_matrix_set(X,i,2,y[i]);
|
||||
|
||||
gsl_vector_set(yy,i,z[i]);
|
||||
gsl_vector_set(w,i,1.0);
|
||||
}
|
||||
|
||||
// Do fit
|
||||
gsl_multifit_linear_workspace *work=gsl_multifit_linear_alloc(n,3);
|
||||
gsl_multifit_wlinear(X,w,yy,c,cov,&chisq,work);
|
||||
gsl_multifit_linear_free(work);
|
||||
|
||||
// Save parameters
|
||||
for (i=0;i<3;i++)
|
||||
a[i]=gsl_vector_get(c,(i));
|
||||
|
||||
gsl_matrix_free(X);
|
||||
gsl_vector_free(yy);
|
||||
gsl_vector_free(w);
|
||||
gsl_vector_free(c);
|
||||
gsl_matrix_free(cov);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a RA and Decl from x and y
|
||||
void reverse(double ra0,double de0,double x,double y,double *ra,double *de)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="TAN";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
x/=3600.;
|
||||
y/=3600.;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celrev(pcode,x,y,&prj,&phi,&theta,&cel,ra,de)) {
|
||||
printf("Error in Projection (celrev)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Add FITS keywords
|
||||
void add_fits_keywords(struct transformation t,char *filename)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
int naxis1,naxis2,naxis3;
|
||||
qfits_header *qh;
|
||||
qfitsdumper qd;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
char com[FITS_LINESZ+1];
|
||||
char lin[FITS_LINESZ+1];
|
||||
FILE *file;
|
||||
float *fbuf;
|
||||
|
||||
naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
naxis3=atoi(qfits_query_hdr(filename,"NAXIS3"));
|
||||
|
||||
fbuf=malloc(sizeof(float)*naxis1*naxis2*naxis3);
|
||||
|
||||
// Read header
|
||||
qh=qfits_header_read(filename);
|
||||
|
||||
ql.xtnum=0;
|
||||
ql.ptype=PTYPE_FLOAT;
|
||||
ql.filename=filename;
|
||||
for (k=0,l=0;k<naxis3;k++) {
|
||||
ql.pnum=k;
|
||||
// Initialize load
|
||||
if (qfitsloader_init(&ql) != 0)
|
||||
printf("Error initializing data loading\n");
|
||||
|
||||
// Test load
|
||||
if (qfits_loadpix(&ql) != 0)
|
||||
printf("Error loading actual data\n");
|
||||
|
||||
for (i=0,m=0;i<naxis1;i++) {
|
||||
for (j=0;j<naxis2;j++) {
|
||||
fbuf[l]=ql.fbuf[m];
|
||||
l++;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sprintf(val,"%e",t.yrms/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRRES2",val," ",NULL);
|
||||
sprintf(val,"%e",t.xrms/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRRES1",val," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CUNIT2","'deg'"," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CUNIT1","'deg'"," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CTYPE2","'DEC--TAN'"," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CTYPE1","'RA---TAN'"," ",NULL);
|
||||
sprintf(val,"%e",t.b[2]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD2_2",val," ",NULL);
|
||||
sprintf(val,"%e",t.b[1]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD2_1",val," ",NULL);
|
||||
sprintf(val,"%e",t.a[2]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD1_2",val," ",NULL);
|
||||
sprintf(val,"%e",t.a[1]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD1_1",val," ",NULL);
|
||||
sprintf(val,"%f",t.de0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRVAL2",val," ",NULL);
|
||||
sprintf(val,"%f",t.ra0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRVAL1",val," ",NULL);
|
||||
sprintf(val,"%f",t.y0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRPIX2",val," ",NULL);
|
||||
sprintf(val,"%f",t.x0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRPIX1",val," ",NULL);
|
||||
|
||||
file=fopen(filename,"w");
|
||||
qfits_header_dump(qh,file);
|
||||
fclose(file);
|
||||
|
||||
qfits_header_destroy(qh);
|
||||
|
||||
qd.filename=filename;
|
||||
qd.npix=naxis1*naxis2*naxis3;
|
||||
qd.ptype=PTYPE_FLOAT;
|
||||
qd.fbuf=fbuf;
|
||||
qd.out_ptype=-32;
|
||||
|
||||
qfits_pixdump(&qd);
|
||||
free(fbuf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Modify FITS keywords
|
||||
void modify_fits_keywords(struct transformation t,char *filename)
|
||||
{
|
||||
char card[FITS_LINESZ+1];
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
char com[FITS_LINESZ+1];
|
||||
|
||||
sprintf(val,"%f",t.x0);
|
||||
keytuple2str(card,"CRPIX1",val,"");
|
||||
qfits_replace_card(filename,"CRPIX1",card);
|
||||
|
||||
sprintf(val,"%f",t.y0);
|
||||
keytuple2str(card,"CRPIX2",val,"");
|
||||
qfits_replace_card(filename,"CRPIX2",card);
|
||||
|
||||
sprintf(val,"%f",t.ra0);
|
||||
keytuple2str(card,"CRVAL1",val,"");
|
||||
qfits_replace_card(filename,"CRVAL1",card);
|
||||
|
||||
sprintf(val,"%f",t.de0);
|
||||
keytuple2str(card,"CRVAL2",val,"");
|
||||
qfits_replace_card(filename,"CRVAL2",card);
|
||||
|
||||
sprintf(val,"%e",t.a[1]/3600.0);
|
||||
keytuple2str(card,"CD1_1",val,"");
|
||||
qfits_replace_card(filename,"CD1_1",card);
|
||||
|
||||
sprintf(val,"%e",t.a[2]/3600.0);
|
||||
keytuple2str(card,"CD1_2",val,"");
|
||||
qfits_replace_card(filename,"CD1_2",card);
|
||||
|
||||
sprintf(val,"%e",t.b[1]/3600.0);
|
||||
keytuple2str(card,"CD2_1",val,"");
|
||||
qfits_replace_card(filename,"CD2_1",card);
|
||||
|
||||
sprintf(val,"%e",t.b[2]/3600.0);
|
||||
keytuple2str(card,"CD2_2",val,"");
|
||||
qfits_replace_card(filename,"CD2_2",card);
|
||||
|
||||
sprintf(val,"%e",t.xrms/3600.0);
|
||||
keytuple2str(card,"CRRES1",val,"");
|
||||
qfits_replace_card(filename,"CRRES1",card);
|
||||
|
||||
sprintf(val,"%e",t.yrms/3600.0);
|
||||
keytuple2str(card,"CRRES2",val,"");
|
||||
qfits_replace_card(filename,"CRRES2",card);
|
||||
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,924 @@
|
|||
/* > deep.c
|
||||
*
|
||||
* 1.00 around 1980 - Felix R. Hoots & Ronald L. Roehrich, from original
|
||||
* DEEP.FOR used in the SGP deep-space models SDP4
|
||||
* and SDP8.
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* Made famous by the spacetrack report No.3:
|
||||
* "Models for Propogation of NORAD Element Sets"
|
||||
* Edited and subsequently distributed by Dr. T. S. Kelso.
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* This conversion by:
|
||||
* Paul S. Crawford and Andrew R. Brooks
|
||||
* Dundee University
|
||||
*
|
||||
* NOTE !
|
||||
* This code is supplied "as is" and without warranty of any sort.
|
||||
*
|
||||
* (c) 1994-2004, Paul Crawford, Andrew Brooks
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* 2.00 psc Mon Dec 19 1994 - Translated from FORTRAN into 'C' (of sorts).
|
||||
*
|
||||
* 2.01 psc Wed Dec 21 1994 - Re-write of the secular integrator from a
|
||||
* messy FORTRAN block in to something which
|
||||
* (hopefully!) is understandable.
|
||||
*
|
||||
* 2.02 psc Thu Dec 22 1994 - Final mods and tested against the FORTRAN
|
||||
* version (using ~12 hour resonant and
|
||||
* geostationary (~24 hour) elements).
|
||||
*
|
||||
* 2.03 psc Mon Jan 02 1995 - Some additional refinements and error-traps.
|
||||
*
|
||||
* 3.00 psc Mon May 29 1995 - Cleaned up for general use & distrabution (to
|
||||
* remove Dundee specific features).
|
||||
*
|
||||
* 3.01 psc Mon Jan 12 2004 - Final fix agreed for "Lyddane bug".
|
||||
* 3.02 psc Mon Jul 03 2006 - Extended range "Lyddane bug" fix.
|
||||
* 3.03 psc Tue Jul 04 2006 - Bug fix for extended range "Lyddane bug" fix.
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static const char SCCSid[] = "@(#)deep.c 3.03 (C) 1995 psc SatLib: Deep Space effects";
|
||||
|
||||
#ifndef NO_DEEP_SPACE
|
||||
|
||||
#include "sgdp4h.h"
|
||||
|
||||
extern long Isat;
|
||||
int Set_LS_zero = 0; /* Set to 1 to zero Lunar-Solar terms at epoch. */
|
||||
|
||||
/* ======================= Function prototypes ====================== */
|
||||
|
||||
static void dot_terms_calculated(void);
|
||||
static void compute_LunarSolar(double tsince);
|
||||
static void thetag(double ep, real *thegr, double *days50);
|
||||
|
||||
/* ===================== Strange constants, etc ===================== */
|
||||
|
||||
#define ZNS ((real)1.19459e-5)
|
||||
#define C1SS ((real)2.9864797e-6)
|
||||
#define ZES ((real)0.01675)
|
||||
|
||||
#define ZNL ((real)1.5835218e-4)
|
||||
#define C1L ((real)4.7968065e-7)
|
||||
#define ZEL ((real)0.0549)
|
||||
|
||||
#define ZCOSIS ((real)0.91744867)
|
||||
#define ZSINIS ((real)0.39785416)
|
||||
#define ZCOSGS ((real)0.1945905)
|
||||
#define ZSINGS ((real)-0.98088458)
|
||||
|
||||
#define Q22 ((real)1.7891679e-6)
|
||||
#define Q31 ((real)2.1460748e-6)
|
||||
#define Q33 ((real)2.2123015e-7)
|
||||
|
||||
#define G22 ((real)5.7686396)
|
||||
#define G32 ((real)0.95240898)
|
||||
#define G44 ((real)1.8014998)
|
||||
#define G52 ((real)1.0508330)
|
||||
#define G54 ((real)4.4108898)
|
||||
|
||||
#define ROOT22 ((real)1.7891679e-6)
|
||||
#define ROOT32 ((real)3.7393792e-7)
|
||||
#define ROOT44 ((real)7.3636953e-9)
|
||||
#define ROOT52 ((real)1.1428639e-7)
|
||||
#define ROOT54 ((real)2.1765803e-9)
|
||||
|
||||
#define THDT ((real)4.37526908801129966e-3)
|
||||
//#define THDT ((real)0.0043752691)
|
||||
|
||||
#define STEP 720.0
|
||||
#define MAX_INTEGRATE (STEP * 10000)
|
||||
#define SIN_EPS (real)(1.0e-12)
|
||||
|
||||
/* ======= Global variables used by dpsec(), from dpinit(). ======== */
|
||||
|
||||
static real eo; /* copy of original eccentricity. */
|
||||
static real xincl; /* copy of original equatorial inclination. */
|
||||
|
||||
static int isynfl=0, iresfl=0;
|
||||
|
||||
static double atime, xli, xni, xnq, xfact;
|
||||
|
||||
static real ssl, ssg, ssh, sse, ssi;
|
||||
static real xlamo, omegaq, omgdt, thgr;
|
||||
static real del1, del2, del3, fasx2, fasx4, fasx6;
|
||||
static real d2201, d2211, d3210, d3222, d4410, d4422;
|
||||
static real d5220, d5232, d5421, d5433;
|
||||
|
||||
static real xnddt, xndot, xldot; /* Integrator terms. */
|
||||
static real xnddt0, xndot0, xldot0; /* Integrator at epoch. */
|
||||
|
||||
/* ======== Global Variables used by dpper(), from dpinit(). ======= */
|
||||
|
||||
static int ilsd=0, ilsz=0;
|
||||
|
||||
static real zmos, se2, se3, si2, si3, sl2, sl3, sl4;
|
||||
static real sgh2, sgh3, sgh4, sh2, sh3;
|
||||
static real zmol, ee2, e3 ,xi2, xi3, xl2, xl3, xl4;
|
||||
static real xgh2, xgh3, xgh4, xh2, xh3;
|
||||
|
||||
static real pe, pinc, pgh, ph, pl;
|
||||
static real pgh0, ph0, pe0, pinc0, pl0; /* Added terms to save the epoch values of perturbations. */
|
||||
|
||||
|
||||
/* ==================================================================
|
||||
|
||||
----------------- DEEP SPACE INITIALIZATION ----------------------
|
||||
|
||||
epoch : Input, epoch time as YYDDD.DDDD as read from 2-line elements.
|
||||
omegao : Input, argument of perigee from elements, radian.
|
||||
xnodeo : Input, right asc. for ascn node from elements, radian.
|
||||
xmo : Input, mean anomaly from elements, radian.
|
||||
orb_eo : Input, eccentricity from elements, dimentionless.
|
||||
orb_xincl : Input, equatorial inclination from elements, radian.
|
||||
aodp : Input, original semi-major axis, earth radii.
|
||||
xlldot : Input, 1st derivative of "mean anomaly" (xmdot), radian/min.
|
||||
omgdot : Input, 1st derivative of arg. per., radian/min.
|
||||
xnodot : Input, 1st derivative of right asc., radian/min.
|
||||
xnodp : Input, original mean motion, radian/min.
|
||||
|
||||
================================================================== */
|
||||
|
||||
int SGDP4_dpinit(double epoch, real omegao, real xnodeo, real xmo,
|
||||
real orb_eo, real orb_xincl, real aodp, double xlldot,
|
||||
real omgdot, real xnodot, double xnodp)
|
||||
{
|
||||
LOCAL_DOUBLE ds50, day, xnodce, bfact=0, gam, c;
|
||||
LOCAL_REAL ctem, sinq, cosq, aqnv, xmao, stem, eqsq, xnoi, ainv2;
|
||||
LOCAL_REAL zcosg, zsing, zcosi, zsini, zcosh, zsinh;
|
||||
LOCAL_REAL cosomo, zcosgl, zcoshl, zcosil, sinomo;
|
||||
LOCAL_REAL xpidot, zsinil, siniq2, cosiq2;
|
||||
LOCAL_REAL rteqsq, zsinhl, zsingl;
|
||||
LOCAL_REAL eoc, sgh, g200, bsq, zmo, xno2;
|
||||
LOCAL_REAL a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
|
||||
LOCAL_REAL x1, x2, x3, x4, x5, x6, x7, x8;
|
||||
LOCAL_REAL z1, z2, z3, z11, z12, z13, z21, z22, z23, z31, z32, z33;
|
||||
LOCAL_REAL s1, s2, s3, s4, s5, s6, s7, cc, ao, eq, se, shdq, si, sl;
|
||||
LOCAL_REAL zx, zy, ze, zn;
|
||||
LOCAL_REAL g201, g211, g310, g300, g322, g410, g422, g520, g533, g521, g532;
|
||||
LOCAL_REAL f220, f221, f311, f321, f322, f330, f441, f442, f522, f523, f542, f543;
|
||||
real siniq, cosiq;
|
||||
real temp0, temp1;
|
||||
int ls, imode=0;
|
||||
int ishq;
|
||||
|
||||
/*
|
||||
Copy the supplied orbital elements to "local" (static to this file)
|
||||
variables and compute common trig values.
|
||||
*/
|
||||
eq = eo = orb_eo;
|
||||
xincl = orb_xincl;
|
||||
|
||||
/* Decide on direct or Lyddane Lunar-Solar perturbations. */
|
||||
ilsd = 0;
|
||||
if(xincl >= (real)0.2) ilsd = 1;
|
||||
|
||||
/* Drop some terms below 3 deg inclination. */
|
||||
ishq = 0;
|
||||
#define SHQT 0.052359877
|
||||
if (xincl >= (real)SHQT) ishq = 1; /* As per reoprt #3. */
|
||||
|
||||
SINCOS(omegao, &sinomo, &cosomo);
|
||||
SINCOS(xnodeo, &sinq, &cosq);
|
||||
SINCOS(xincl, &siniq, &cosiq);
|
||||
|
||||
if (fabs(siniq) <= SIN_EPS)
|
||||
{
|
||||
siniq = SIGN(SIN_EPS, siniq);
|
||||
}
|
||||
|
||||
cosiq2 = cosiq * cosiq;
|
||||
siniq2 = siniq * siniq;
|
||||
|
||||
ao = aodp;
|
||||
omgdt = omgdot;
|
||||
eqsq = eo * eo;
|
||||
bsq = (real)1.0 - eqsq;
|
||||
rteqsq = SQRT(bsq);
|
||||
thetag(epoch, &thgr, &ds50);
|
||||
|
||||
/*printf("# epoch = %.8f ds50 = %.8f thgr = %f\n", epoch, ds50, DEG(thgr));*/
|
||||
|
||||
xnq = xnodp;
|
||||
aqnv = (real)1.0 / ao;
|
||||
xmao = xmo;
|
||||
xpidot = omgdt + xnodot;
|
||||
omegaq = omegao;
|
||||
|
||||
/* INITIALIZE LUNAR SOLAR TERMS */
|
||||
|
||||
day = ds50 + 18261.5;
|
||||
|
||||
xnodce = 4.523602 - day * 9.2422029e-4;
|
||||
temp0 = (real)fmod(xnodce, TWOPI);
|
||||
SINCOS(temp0, &stem, &ctem);
|
||||
|
||||
zcosil = (real)0.91375164 - ctem * (real)0.03568096;
|
||||
zsinil = SQRT((real)1.0 - zcosil * zcosil);
|
||||
zsinhl = stem * (real)0.089683511 / zsinil;
|
||||
zcoshl = SQRT((real)1.0 - zsinhl * zsinhl);
|
||||
c = day * 0.2299715 + 4.7199672;
|
||||
gam = day * 0.001944368 + 5.8351514;
|
||||
zmol = (real)MOD2PI(c - gam);
|
||||
zx = stem * (real)0.39785416 / zsinil;
|
||||
zy = zcoshl * ctem + zsinhl * (real)0.91744867 * stem;
|
||||
zx = ATAN2(zx, zy);
|
||||
zx = (real)fmod(gam + zx - xnodce, TWOPI);
|
||||
SINCOS(zx, &zsingl, &zcosgl);
|
||||
zmos = (real)MOD2PI(day * 0.017201977 + 6.2565837);
|
||||
|
||||
/* DO SOLAR TERMS */
|
||||
|
||||
zcosg = ZCOSGS;
|
||||
zsing = ZSINGS;
|
||||
zcosi = ZCOSIS;
|
||||
zsini = ZSINIS;
|
||||
zcosh = cosq;
|
||||
zsinh = sinq;
|
||||
cc = C1SS;
|
||||
zn = ZNS;
|
||||
ze = ZES;
|
||||
zmo = zmos;
|
||||
xnoi = (real)(1.0 / xnq);
|
||||
|
||||
for(ls = 0; ls < 2; ls++)
|
||||
{
|
||||
a1 = zcosg * zcosh + zsing * zcosi * zsinh;
|
||||
a3 = -zsing * zcosh + zcosg * zcosi * zsinh;
|
||||
a7 = -zcosg * zsinh + zsing * zcosi * zcosh;
|
||||
a8 = zsing * zsini;
|
||||
a9 = zsing * zsinh + zcosg * zcosi * zcosh;
|
||||
a10 = zcosg * zsini;
|
||||
a2 = cosiq * a7 + siniq * a8;
|
||||
a4 = cosiq * a9 + siniq * a10;
|
||||
a5 = -siniq * a7 + cosiq * a8;
|
||||
a6 = -siniq * a9 + cosiq * a10;
|
||||
|
||||
x1 = a1 * cosomo + a2 * sinomo;
|
||||
x2 = a3 * cosomo + a4 * sinomo;
|
||||
x3 = -a1 * sinomo + a2 * cosomo;
|
||||
x4 = -a3 * sinomo + a4 * cosomo;
|
||||
x5 = a5 * sinomo;
|
||||
x6 = a6 * sinomo;
|
||||
x7 = a5 * cosomo;
|
||||
x8 = a6 * cosomo;
|
||||
|
||||
z31 = x1 * (real)12.0 * x1 - x3 * (real)3.0 * x3;
|
||||
z32 = x1 * (real)24.0 * x2 - x3 * (real)6.0 * x4;
|
||||
z33 = x2 * (real)12.0 * x2 - x4 * (real)3.0 * x4;
|
||||
z1 = (a1 * a1 + a2 * a2) * (real)3.0 + z31 * eqsq;
|
||||
z2 = (a1 * a3 + a2 * a4) * (real)6.0 + z32 * eqsq;
|
||||
z3 = (a3 * a3 + a4 * a4) * (real)3.0 + z33 * eqsq;
|
||||
z11 = a1 * (real)-6.0 * a5 + eqsq * (x1 * (real)-24.0 * x7 - x3 *
|
||||
(real)6.0 * x5);
|
||||
z12 = (a1 * a6 + a3 * a5) * (real)-6.0 + eqsq * ((x2 * x7 +
|
||||
x1 * x8) * (real)-24.0 - (x3 * x6 + x4 * x5) * (real)6.0);
|
||||
z13 = a3 * (real)-6.0 * a6 + eqsq * (x2 * (real)-24.0 * x8 - x4 *
|
||||
(real)6.0 * x6);
|
||||
z21 = a2 * (real)6.0 * a5 + eqsq * (x1 * (real)24.0 * x5 -
|
||||
x3 * (real)6.0 * x7);
|
||||
z22 = (a4 * a5 + a2 * a6) * (real)6.0 + eqsq * ((x2 * x5 + x1 * x6) *
|
||||
(real)24.0 - (x4 * x7 + x3 * x8) * (real)6.0);
|
||||
z23 = a4 * (real)6.0 * a6 + eqsq * (x2 * (real)24.0 * x6 - x4 *
|
||||
(real)6.0 * x8);
|
||||
z1 = z1 + z1 + bsq * z31;
|
||||
z2 = z2 + z2 + bsq * z32;
|
||||
z3 = z3 + z3 + bsq * z33;
|
||||
s3 = cc * xnoi;
|
||||
s2 = s3 * (real)-0.5 / rteqsq;
|
||||
s4 = s3 * rteqsq;
|
||||
s1 = eq * (real)-15.0 * s4;
|
||||
s5 = x1 * x3 + x2 * x4;
|
||||
s6 = x2 * x3 + x1 * x4;
|
||||
s7 = x2 * x4 - x1 * x3;
|
||||
se = s1 * zn * s5;
|
||||
si = s2 * zn * (z11 + z13);
|
||||
sl = -zn * s3 * (z1 + z3 - (real)14.0 - eqsq * (real)6.0);
|
||||
sgh = s4 * zn * (z31 + z33 - (real)6.0);
|
||||
|
||||
shdq = 0;
|
||||
if(ishq)
|
||||
{
|
||||
real sh = -zn * s2 * (z21 + z23);
|
||||
shdq = sh / siniq;
|
||||
}
|
||||
|
||||
ee2 = s1 * (real)2.0 * s6;
|
||||
e3 = s1 * (real)2.0 * s7;
|
||||
xi2 = s2 * (real)2.0 * z12;
|
||||
xi3 = s2 * (real)2.0 * (z13 - z11);
|
||||
xl2 = s3 * (real)-2.0 * z2;
|
||||
xl3 = s3 * (real)-2.0 * (z3 - z1);
|
||||
xl4 = s3 * (real)-2.0 * ((real)-21.0 - eqsq * (real)9.0) * ze;
|
||||
xgh2 = s4 * (real)2.0 * z32;
|
||||
xgh3 = s4 * (real)2.0 * (z33 - z31);
|
||||
xgh4 = s4 * (real)-18.0 * ze;
|
||||
xh2 = s2 * (real)-2.0 * z22;
|
||||
xh3 = s2 * (real)-2.0 * (z23 - z21);
|
||||
|
||||
if (ls == 1) break;
|
||||
|
||||
/* DO LUNAR TERMS */
|
||||
|
||||
sse = se;
|
||||
ssi = si;
|
||||
ssl = sl;
|
||||
ssh = shdq;
|
||||
ssg = sgh - cosiq * ssh;
|
||||
se2 = ee2;
|
||||
si2 = xi2;
|
||||
sl2 = xl2;
|
||||
sgh2 = xgh2;
|
||||
sh2 = xh2;
|
||||
se3 = e3;
|
||||
si3 = xi3;
|
||||
sl3 = xl3;
|
||||
sgh3 = xgh3;
|
||||
sh3 = xh3;
|
||||
sl4 = xl4;
|
||||
sgh4 = xgh4;
|
||||
zcosg = zcosgl;
|
||||
zsing = zsingl;
|
||||
zcosi = zcosil;
|
||||
zsini = zsinil;
|
||||
zcosh = zcoshl * cosq + zsinhl * sinq;
|
||||
zsinh = sinq * zcoshl - cosq * zsinhl;
|
||||
zn = ZNL;
|
||||
cc = C1L;
|
||||
ze = ZEL;
|
||||
zmo = zmol;
|
||||
}
|
||||
|
||||
sse += se;
|
||||
ssi += si;
|
||||
ssl += sl;
|
||||
ssg += sgh - cosiq * shdq;
|
||||
ssh += shdq;
|
||||
|
||||
if (xnq < 0.0052359877 && xnq > 0.0034906585)
|
||||
{
|
||||
/* 24h SYNCHRONOUS RESONANCE TERMS INITIALIZATION */
|
||||
iresfl = 1;
|
||||
isynfl = 1;
|
||||
g200 = eqsq * (eqsq * (real)0.8125 - (real)2.5) + (real)1.0;
|
||||
g310 = eqsq * (real)2.0 + (real)1.0;
|
||||
g300 = eqsq * (eqsq * (real)6.60937 - (real)6.0) + (real)1.0;
|
||||
f220 = (cosiq + (real)1.0) * (real)0.75 * (cosiq + (real)1.0);
|
||||
f311 = siniq * (real)0.9375 * siniq * (cosiq * (real)3.0 +
|
||||
(real)1.0) - (cosiq + (real)1.0) * (real)0.75;
|
||||
f330 = cosiq + (real)1.0;
|
||||
f330 = f330 * (real)1.875 * f330 * f330;
|
||||
del1 = (real)3.0 * (real)(xnq * xnq * aqnv * aqnv);
|
||||
del2 = del1 * (real)2.0 * f220 * g200 * Q22;
|
||||
del3 = del1 * (real)3.0 * f330 * g300 * Q33 * aqnv;
|
||||
del1 = del1 * f311 * g310 * Q31 * aqnv;
|
||||
fasx2 = (real)0.13130908;
|
||||
fasx4 = (real)2.8843198;
|
||||
fasx6 = (real)0.37448087;
|
||||
xlamo = xmao + xnodeo + omegao - thgr;
|
||||
bfact = xlldot + xpidot - THDT;
|
||||
bfact += (double)(ssl + ssg + ssh);
|
||||
}
|
||||
else if (xnq >= 0.00826 && xnq <= 0.00924 && eq >= (real)0.5)
|
||||
{
|
||||
/* GEOPOTENTIAL RESONANCE INITIALIZATION FOR 12 HOUR ORBITS */
|
||||
iresfl = 1;
|
||||
isynfl = 0;
|
||||
eoc = eq * eqsq;
|
||||
g201 = (real)-0.306 - (eq - (real)0.64) * (real)0.44;
|
||||
|
||||
if (eq <= (real)0.65)
|
||||
{
|
||||
g211 = (real)3.616 - eq * (real)13.247 + eqsq * (real)16.29;
|
||||
g310 = eq * (real)117.39 - (real)19.302 - eqsq * (real)228.419 + eoc * (real)156.591;
|
||||
g322 = eq * (real)109.7927 - (real)18.9068 - eqsq * (real)214.6334 + eoc * (real)146.5816;
|
||||
g410 = eq * (real)242.694 - (real)41.122 - eqsq * (real)471.094 + eoc * (real)313.953;
|
||||
g422 = eq * (real)841.88 - (real)146.407 - eqsq * (real)1629.014 + eoc * (real)1083.435;
|
||||
g520 = eq * (real)3017.977 - (real)532.114 - eqsq * 5740.032 + eoc * (real)3708.276;
|
||||
}
|
||||
else
|
||||
{
|
||||
g211 = eq * (real)331.819 - (real)72.099 - eqsq * (real)508.738 + eoc * (real)266.724;
|
||||
g310 = eq * (real)1582.851 - (real)346.844 - eqsq * (real)2415.925 + eoc * (real)1246.113;
|
||||
g322 = eq * (real)1554.908 - (real)342.585 - eqsq * (real)2366.899 + eoc * (real)1215.972;
|
||||
g410 = eq * (real)4758.686 - (real)1052.797 - eqsq * (real)7193.992 + eoc * (real)3651.957;
|
||||
g422 = eq * (real)16178.11 - (real)3581.69 - eqsq * (real)24462.77 + eoc * (real)12422.52;
|
||||
|
||||
if (eq <= (real)0.715)
|
||||
{
|
||||
g520 = (real)1464.74 - eq * (real)4664.75 + eqsq * (real)3763.64;
|
||||
}
|
||||
else
|
||||
{
|
||||
g520 = eq * (real)29936.92 - (real)5149.66 - eqsq * (real)54087.36 + eoc * (real)31324.56;
|
||||
}
|
||||
}
|
||||
|
||||
if (eq < (real)0.7)
|
||||
{
|
||||
g533 = eq * (real)4988.61 - (real)919.2277 - eqsq * (real)9064.77 + eoc * (real)5542.21;
|
||||
g521 = eq * (real)4568.6173 - (real)822.71072 - eqsq * (real)8491.4146 + eoc * (real)5337.524;
|
||||
g532 = eq * (real)4690.25 - (real)853.666 - eqsq * (real)8624.77 + eoc * (real)5341.4;
|
||||
}
|
||||
else
|
||||
{
|
||||
g533 = eq * (real)161616.52 - (real)37995.78 - eqsq * (real)229838.2 + eoc * (real)109377.94;
|
||||
g521 = eq * (real)218913.95 - (real)51752.104 - eqsq * (real)309468.16 + eoc * (real)146349.42;
|
||||
g532 = eq * (real)170470.89 - (real)40023.88 - eqsq * (real)242699.48 + eoc * (real)115605.82;
|
||||
}
|
||||
|
||||
f220 = (cosiq * (real)2.0 + (real)1.0 + cosiq2) * (real)0.75;
|
||||
f221 = siniq2 * (real)1.5;
|
||||
f321 = siniq * (real)1.875 * ((real)1.0 - cosiq * (real)2.0 - cosiq2 * (real)3.0);
|
||||
f322 = siniq * (real)-1.875 * (cosiq * (real)2.0 + (real)1.0 - cosiq2 * (real)3.0);
|
||||
f441 = siniq2 * (real)35.0 * f220;
|
||||
f442 = siniq2 * (real)39.375 * siniq2;
|
||||
f522 = siniq * (real)9.84375 * (siniq2 * ((real)1.0 - cosiq *
|
||||
(real)2.0 - cosiq2 * (real)5.0) + (cosiq * (real)4.0 -
|
||||
(real)2.0 + cosiq2 * (real)6.0) * (real)0.33333333);
|
||||
f523 = siniq * (siniq2 * (real)4.92187512 * ((real)-2.0 - cosiq *
|
||||
(real)4.0 + cosiq2 * (real)10.0) + (cosiq * (real)2.0 +
|
||||
(real)1.0 - cosiq2 * (real)3.0) * (real)6.56250012);
|
||||
f542 = siniq * (real)29.53125 * ((real)2.0 - cosiq * (real)8.0 +
|
||||
cosiq2 * (cosiq * (real)8.0 - (real)12.0 + cosiq2 *
|
||||
(real)10.0));
|
||||
f543 = siniq * (real)29.53125 * ((real)-2.0 - cosiq * (real)8.0 +
|
||||
cosiq2 * (cosiq * (real)8.0 + (real)12.0 - cosiq2 *
|
||||
(real)10.0));
|
||||
xno2 = (real)(xnq * xnq);
|
||||
ainv2 = aqnv * aqnv;
|
||||
temp1 = xno2 * (real)3.0 * ainv2;
|
||||
temp0 = temp1 * ROOT22;
|
||||
d2201 = temp0 * f220 * g201;
|
||||
d2211 = temp0 * f221 * g211;
|
||||
temp1 *= aqnv;
|
||||
temp0 = temp1 * ROOT32;
|
||||
d3210 = temp0 * f321 * g310;
|
||||
d3222 = temp0 * f322 * g322;
|
||||
temp1 *= aqnv;
|
||||
temp0 = temp1 * (real)2.0 * ROOT44;
|
||||
d4410 = temp0 * f441 * g410;
|
||||
d4422 = temp0 * f442 * g422;
|
||||
temp1 *= aqnv;
|
||||
temp0 = temp1 * ROOT52;
|
||||
d5220 = temp0 * f522 * g520;
|
||||
d5232 = temp0 * f523 * g532;
|
||||
temp0 = temp1 * (real)2.0 * ROOT54;
|
||||
d5421 = temp0 * f542 * g521;
|
||||
d5433 = temp0 * f543 * g533;
|
||||
xlamo = xmao + xnodeo + xnodeo - thgr - thgr;
|
||||
bfact = xlldot + xnodot + xnodot - THDT - THDT;
|
||||
bfact += (double)(ssl + ssh + ssh);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NON RESONANT ORBITS */
|
||||
iresfl = 0;
|
||||
isynfl = 0;
|
||||
}
|
||||
|
||||
if(iresfl == 0)
|
||||
{
|
||||
/* Non-resonant orbits. */
|
||||
imode = SGDP4_DEEP_NORM;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* INITIALIZE INTEGRATOR */
|
||||
xfact = bfact - xnq;
|
||||
xli = (double)xlamo;
|
||||
xni = xnq;
|
||||
atime = 0.0;
|
||||
|
||||
dot_terms_calculated();
|
||||
|
||||
/* Save the "dot" terms for integrator re-start. */
|
||||
xnddt0 = xnddt;
|
||||
xndot0 = xndot;
|
||||
xldot0 = xldot;
|
||||
|
||||
if (isynfl)
|
||||
imode = SGDP4_DEEP_SYNC;
|
||||
else
|
||||
imode = SGDP4_DEEP_RESN;
|
||||
}
|
||||
|
||||
/* Set up for original mode (LS terms at epoch non-zero). */
|
||||
ilsz = 0;
|
||||
pgh0 = ph0 = pe0 = pinc0 = pl0 = (real)0.0;
|
||||
|
||||
if(Set_LS_zero)
|
||||
{
|
||||
/* Save the epoch case Lunar-Solar terms to remove this bias for
|
||||
* actual computations later on.
|
||||
* Not sure if this is a good idea.
|
||||
*/
|
||||
compute_LunarSolar(0.0);
|
||||
|
||||
pgh0 = pgh;
|
||||
ph0 = ph;
|
||||
pe0 = pe;
|
||||
pinc0 = pinc;
|
||||
pl0 = pl;
|
||||
ilsz = 1;
|
||||
}
|
||||
|
||||
|
||||
return imode;
|
||||
} /* SGDP4_dpinit */
|
||||
|
||||
/* =====================================================================
|
||||
|
||||
------------- ENTRANCE FOR DEEP SPACE SECULAR EFFECTS ---------------
|
||||
|
||||
xll : Input/Output, modified "mean anomaly" or "mean longitude".
|
||||
omgasm : Input/Output, modified argument of perigee.
|
||||
xnodes : Input/Output, modified right asc of ascn node.
|
||||
em : Input/Output, modified eccentricity.
|
||||
xinc : Input/Output, modified inclination.
|
||||
|
||||
xn : Output, modified period from 'xnodp'.
|
||||
|
||||
tsince : Input, time from epoch (minutes).
|
||||
|
||||
===================================================================== */
|
||||
|
||||
int SGDP4_dpsec(double *xll, real *omgasm, real *xnodes, real *em,
|
||||
real *xinc, double *xn, double tsince)
|
||||
{
|
||||
LOCAL_DOUBLE delt, ft, xl;
|
||||
real temp0;
|
||||
|
||||
*xll += ssl * tsince;
|
||||
*omgasm += ssg * tsince;
|
||||
*xnodes += ssh * tsince;
|
||||
*em += sse * tsince;
|
||||
*xinc += ssi * tsince;
|
||||
|
||||
if (iresfl == 0) return 0;
|
||||
|
||||
/*
|
||||
* A minor increase in some efficiency can be had by restarting if
|
||||
* the new time is closer to epoch than to the old integrated
|
||||
* time. This also forces a re-start on a change in sign (i.e. going
|
||||
* through zero time) as then we have |tsince - atime| > |tsince|
|
||||
* as well. Second test is for stepping back towards zero, forcing a restart
|
||||
* if close enough rather than integrating to zero.
|
||||
*/
|
||||
#define AHYST 1.0
|
||||
/* Most accurate (OK, most _consistant_) method. Restart if need to
|
||||
* integrate 'backwards' significantly from current point.
|
||||
*/
|
||||
if(fabs(tsince) < STEP ||
|
||||
(atime > 0.0 && tsince < atime - AHYST) ||
|
||||
(atime < 0.0 && tsince > atime + AHYST))
|
||||
{
|
||||
/* Epoch restart if we are at, or have crossed, tsince==0 */
|
||||
atime = 0.0;
|
||||
xni = xnq;
|
||||
xli = (double)xlamo;
|
||||
/* Restore the old "dot" terms. */
|
||||
xnddt = xnddt0;
|
||||
xndot = xndot0;
|
||||
xldot = xldot0;
|
||||
}
|
||||
|
||||
ft = tsince - atime;
|
||||
|
||||
if (fabs(ft) > MAX_INTEGRATE)
|
||||
{
|
||||
fatal_error("SGDP4_dpsec: Integration limit reached");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fabs(ft) >= STEP)
|
||||
{
|
||||
/*
|
||||
Do integration if required. Find the step direction to
|
||||
make 'atime' catch up with 'tsince'.
|
||||
*/
|
||||
delt = (tsince >= atime ? STEP : -STEP);
|
||||
|
||||
do {
|
||||
/* INTEGRATOR (using the last "dot" terms). */
|
||||
xli += delt * (xldot + delt * (real)0.5 * xndot);
|
||||
xni += delt * (xndot + delt * (real)0.5 * xnddt);
|
||||
atime += delt;
|
||||
|
||||
dot_terms_calculated();
|
||||
|
||||
/* Are we close enough now ? */
|
||||
ft = tsince - atime;
|
||||
} while (fabs(ft) >= STEP);
|
||||
}
|
||||
|
||||
xl = xli + ft * (xldot + ft * (real)0.5 * xndot);
|
||||
*xn = xni + ft * (xndot + ft * (real)0.5 * xnddt);
|
||||
|
||||
temp0 = -(*xnodes) + thgr + tsince * THDT;
|
||||
|
||||
if (isynfl == 0)
|
||||
*xll = xl + temp0 + temp0;
|
||||
else
|
||||
*xll = xl - *omgasm + temp0;
|
||||
|
||||
return 0;
|
||||
} /* SGDP4_dpsec */
|
||||
|
||||
/* =====================================================================
|
||||
|
||||
Here we do the "dot" terms for the integrator. Separate function so we
|
||||
can call when initialising and save the atime==0.0 values for later
|
||||
epoch re-start of the integrator.
|
||||
|
||||
===================================================================== */
|
||||
|
||||
static void dot_terms_calculated(void)
|
||||
{
|
||||
LOCAL_DOUBLE x2li, x2omi, xomi;
|
||||
|
||||
/* DOT TERMS CALCULATED */
|
||||
if (isynfl)
|
||||
{
|
||||
xndot = del1 * SIN(xli - fasx2)
|
||||
+ del2 * SIN((xli - fasx4) * (real)2.0)
|
||||
+ del3 * SIN((xli - fasx6) * (real)3.0);
|
||||
|
||||
xnddt = del1 * COS(xli - fasx2)
|
||||
+ del2 * COS((xli - fasx4) * (real)2.0) * (real)2.0
|
||||
+ del3 * COS((xli - fasx6) * (real)3.0) * (real)3.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
xomi = omegaq + omgdt * atime;
|
||||
x2omi = xomi + xomi;
|
||||
x2li = xli + xli;
|
||||
|
||||
xndot = d2201 * SIN(x2omi + xli - G22)
|
||||
+ d2211 * SIN(xli - G22)
|
||||
+ d3210 * SIN(xomi + xli - G32)
|
||||
+ d3222 * SIN(-xomi + xli - G32)
|
||||
+ d5220 * SIN(xomi + xli - G52)
|
||||
+ d5232 * SIN(-xomi + xli - G52)
|
||||
+ d4410 * SIN(x2omi + x2li - G44)
|
||||
+ d4422 * SIN(x2li - G44)
|
||||
+ d5421 * SIN(xomi + x2li - G54)
|
||||
+ d5433 * SIN(-xomi + x2li - G54);
|
||||
|
||||
xnddt = d2201 * COS(x2omi + xli - G22)
|
||||
+ d2211 * COS(xli - G22)
|
||||
+ d3210 * COS(xomi + xli - G32)
|
||||
+ d3222 * COS(-xomi + xli - G32)
|
||||
+ d5220 * COS(xomi + xli - G52)
|
||||
+ d5232 * COS(-xomi + xli - G52)
|
||||
+ (d4410 * COS(x2omi + x2li - G44)
|
||||
+ d4422 * COS(x2li - G44)
|
||||
+ d5421 * COS(xomi + x2li - G54)
|
||||
+ d5433 * COS(-xomi + x2li - G54)) * (real)2.0;
|
||||
}
|
||||
|
||||
xldot = (real)(xni + xfact);
|
||||
xnddt *= xldot;
|
||||
|
||||
} /* dot_terms_calculated */
|
||||
|
||||
/* =====================================================================
|
||||
|
||||
---------------- ENTRANCES FOR LUNAR-SOLAR PERIODICS ----------------
|
||||
|
||||
em : Input/Output, modified eccentricity.
|
||||
xinc : Input/Output, modified inclination.
|
||||
omgasm : Input/Output, modified argument of perigee.
|
||||
xnodes : Input/Output, modified right asc of ascn node.
|
||||
xll : Input/Output, modified "mean anomaly" or "mean longitude".
|
||||
tsince : Input, time from epoch (minutes).
|
||||
|
||||
===================================================================== */
|
||||
|
||||
int SGDP4_dpper(real *em, real *xinc, real *omgasm, real *xnodes,
|
||||
double *xll, double tsince)
|
||||
{
|
||||
real sinis, cosis;
|
||||
|
||||
compute_LunarSolar(tsince);
|
||||
|
||||
*xinc += pinc;
|
||||
*em += pe;
|
||||
|
||||
/* Spacetrack report #3 has sin/cos from before perturbations
|
||||
* added to xinc (oldxinc), but apparently report # 6 has then
|
||||
* from after they are added.
|
||||
*/
|
||||
SINCOS(*xinc, &sinis, &cosis);
|
||||
|
||||
if (ilsd)
|
||||
{
|
||||
/* APPLY PERIODICS DIRECTLY */
|
||||
real tmp_ph;
|
||||
tmp_ph = ph / sinis;
|
||||
|
||||
*omgasm += pgh - cosis * tmp_ph;
|
||||
*xnodes += tmp_ph;
|
||||
*xll += pl;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* APPLY PERIODICS WITH LYDDANE MODIFICATION */
|
||||
LOCAL_REAL alfdp, betdp, dalf, dbet, xls, dls;
|
||||
LOCAL_REAL sinok, cosok;
|
||||
int ishift;
|
||||
real tmp, oldxnode = (*xnodes);
|
||||
|
||||
SINCOS(*xnodes, &sinok, &cosok);
|
||||
alfdp = sinis * sinok;
|
||||
betdp = sinis * cosok;
|
||||
dalf = ph * cosok + pinc * cosis * sinok;
|
||||
dbet = -ph * sinok + pinc * cosis * cosok;
|
||||
alfdp += dalf;
|
||||
betdp += dbet;
|
||||
xls = (real)*xll + *omgasm + cosis * *xnodes;
|
||||
dls = pl + pgh - pinc * *xnodes * sinis;
|
||||
xls += dls;
|
||||
*xnodes = ATAN2(alfdp, betdp);
|
||||
|
||||
/* Get perturbed xnodes in to same quadrant as original. */
|
||||
ishift = NINT((oldxnode - (*xnodes))/TWOPI);
|
||||
*xnodes += (real)(TWOPI * ishift);
|
||||
|
||||
*xll += (double)pl;
|
||||
*omgasm = xls - (real)*xll - cosis * (*xnodes);
|
||||
}
|
||||
|
||||
return 0;
|
||||
} /* SGDP4_dpper */
|
||||
|
||||
/* =====================================================================
|
||||
Do the Lunar-Solar terms for the SGDP4_dpper() function (normally only
|
||||
every 1/2 hour needed. Seperate function so initialisng could save the
|
||||
epoch terms to zero them. Not sure if this is a good thing (some believe
|
||||
it the way the equations were intended) as the two-line elements may
|
||||
be computed to give the right answer with out this (which I would hope
|
||||
as it would make predictions consistant with the 'official' model
|
||||
code).
|
||||
===================================================================== */
|
||||
|
||||
static void compute_LunarSolar(double tsince)
|
||||
{
|
||||
LOCAL_REAL sinzf, coszf;
|
||||
LOCAL_REAL f2, f3, zf, zm;
|
||||
LOCAL_REAL sel, sil, ses, sll, sis, sls;
|
||||
LOCAL_REAL sghs, shs, sghl, shl;
|
||||
|
||||
/* Update Solar terms. */
|
||||
zm = zmos + ZNS * tsince;
|
||||
zf = zm + ZES * (real)2.0 * SIN(zm);
|
||||
SINCOS(zf, &sinzf, &coszf);
|
||||
f2 = sinzf * (real)0.5 * sinzf - (real)0.25;
|
||||
f3 = sinzf * (real)-0.5 * coszf;
|
||||
ses = se2 * f2 + se3 * f3;
|
||||
sis = si2 * f2 + si3 * f3;
|
||||
sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf;
|
||||
|
||||
sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf;
|
||||
shs = sh2 * f2 + sh3 * f3;
|
||||
|
||||
/* Update Lunar terms. */
|
||||
zm = zmol + ZNL * tsince;
|
||||
zf = zm + ZEL * (real)2.0 * SIN(zm);
|
||||
SINCOS(zf, &sinzf, &coszf);
|
||||
f2 = sinzf * (real)0.5 * sinzf - (real)0.25;
|
||||
f3 = sinzf * (real)-0.5 * coszf;
|
||||
sel = ee2 * f2 + e3 * f3;
|
||||
sil = xi2 * f2 + xi3 * f3;
|
||||
sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf;
|
||||
|
||||
sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf;
|
||||
shl = xh2 * f2 + xh3 * f3;
|
||||
|
||||
/* Save computed values to calling structure. */
|
||||
pgh = sghs + sghl;
|
||||
ph = shs + shl;
|
||||
pe = ses + sel;
|
||||
pinc = sis + sil;
|
||||
pl = sls + sll;
|
||||
|
||||
if (ilsz)
|
||||
{
|
||||
/* Correct for previously saved epoch terms. */
|
||||
pgh -= pgh0;
|
||||
ph -= ph0;
|
||||
pe -= pe0;
|
||||
pinc -= pinc0;
|
||||
pl -= pl0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
This function converts the epoch time (in the form of YYDDD.DDDDDDDD,
|
||||
exactly as it appears in the two-line elements) into days from 00:00:00
|
||||
hours Jan 1st 1950 UTC. Also it computes the right ascencion of Greenwich
|
||||
at the epoch time, but not in a very accurate manner. However, the same
|
||||
method is used here to allow exact comparason with the original FORTRAN
|
||||
versions of the programs. The calling arguments are:
|
||||
|
||||
ep : Input, epoch time of elements (as read from 2-line data).
|
||||
thegr : Output, right ascensionm of Greenwich at epoch, radian.
|
||||
days50 : Output, days from Jan 1st 1950 00:00:00 UTC.
|
||||
|
||||
===================================================================== */
|
||||
|
||||
#define THETAG 2
|
||||
|
||||
/* Version like sat_code. */
|
||||
#define J1900 (2451545.5 - 36525. - 1.)
|
||||
#define SECDAY (86400.0)
|
||||
|
||||
#define C1 (1.72027916940703639E-2)
|
||||
#define C1P2P (C1 + TWOPI)
|
||||
#define THGR70 (1.7321343856509374)
|
||||
#define FK5R (5.07551419432269442E-15)
|
||||
|
||||
|
||||
static void thetag(double ep, real *thegr, double *days50)
|
||||
{
|
||||
double d;
|
||||
long n, jy;
|
||||
double jd, theta;
|
||||
|
||||
jy = (long)((ep + 2.0e-7) * 0.001); /* Extract the year. */
|
||||
d = ep - jy * 1.0e3; /* And then the day of year. */
|
||||
|
||||
/* Assume " 8" is 1980, or more sensibly 2008 ? */
|
||||
/*
|
||||
if (jy < 10) jy += 80;
|
||||
*/
|
||||
if (jy < 50) jy += 100;
|
||||
|
||||
if (jy < 70) /* Fix for leap years ? */
|
||||
n = (jy - 72) / 4;
|
||||
else
|
||||
n = (jy - 69) / 4;
|
||||
|
||||
*days50 = (jy - 70) * 365.0 + 7305.0 + n + d;
|
||||
|
||||
jd = d + J1900 + jy * 365. + ((jy - 1) / 4);
|
||||
|
||||
#if THETAG == 0
|
||||
/* Original report #3 code. */
|
||||
theta = *days50 * 6.3003880987 + 1.72944494;
|
||||
#elif THETAG == 1
|
||||
{
|
||||
/* Method from project pluto code. */
|
||||
/* Reference: The 1992 Astronomical Almanac, page B6. */
|
||||
const double omega_E = 1.00273790934; /* Earth rotations per sidereal day (non-constant) */
|
||||
const double UT = fmod(jd + 0.5, 1.0);
|
||||
double t_cen, GMST;
|
||||
|
||||
t_cen = (jd - UT - 2451545.0) / 36525.0;
|
||||
GMST = 24110.54841 + t_cen * (8640184.812866 + t_cen * (0.093104 - t_cen * 6.2E-6));
|
||||
|
||||
GMST = fmod( GMST + SECDAY * omega_E * UT, SECDAY);
|
||||
|
||||
if(GMST < 0.0) GMST += SECDAY;
|
||||
|
||||
theta = TWOPI * GMST / SECDAY;
|
||||
}
|
||||
#elif THETAG == 2
|
||||
{
|
||||
/* Method from SGP4SUB.F code. */
|
||||
double ts70, ds70, trfac;
|
||||
long ids70;
|
||||
|
||||
ts70 = (*days50) - 7305.0;
|
||||
ids70 = (long)(ts70 + 1.0e-8);
|
||||
ds70 = ids70;
|
||||
|
||||
trfac = ts70 - ds70;
|
||||
|
||||
/* CALCULATE GREENWICH LOCATION AT EPOCH */
|
||||
theta = THGR70 + C1*ds70 + C1P2P*trfac + ts70*ts70*FK5R;
|
||||
}
|
||||
#else
|
||||
#error 'Unknown method for theta-G calculation'
|
||||
#endif
|
||||
|
||||
theta = fmod(theta, TWOPI);
|
||||
if (theta < 0.0) theta += TWOPI;
|
||||
|
||||
*thegr = (real)theta;
|
||||
|
||||
} /* thetag */
|
||||
|
||||
|
||||
#endif /* !NO_DEEP_SPACE */
|
|
@ -0,0 +1,124 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define TINY 1.0e-10
|
||||
#define NMAX 100000
|
||||
#define SWAP(a,b) {(a)+=(b);(b)=(a)-(b);(a)-=(b);}
|
||||
|
||||
// Downhill Simplex Minimization
|
||||
int dsmin(double **p,double *y,int n,double ftol,double (*func)(double *))
|
||||
{
|
||||
int i,j,nfunk=0;
|
||||
int ihi,ilo,ise;
|
||||
double *ptry,*pmid,*psum;
|
||||
double tol,ytry,rtol,ysave;
|
||||
double *vector_sum(double **,int);
|
||||
double dsmod(double **,double *,double *,int,double (*func)(double *),int,double);
|
||||
|
||||
// Allocate memory
|
||||
psum=(double *) malloc(sizeof(double) * n);
|
||||
|
||||
// Get function values
|
||||
for (i=0;i<=n;i++)
|
||||
y[i]=func(p[i]);
|
||||
|
||||
// Sum vectors
|
||||
psum=vector_sum(p,n);
|
||||
|
||||
// Start forever loop
|
||||
for (;;) {
|
||||
// Find high and low point
|
||||
ilo=0;
|
||||
ihi = (y[0]>y[1]) ? (ise=1,0) : (ise=0,1);
|
||||
for (i=0;i<=n;i++) {
|
||||
if (y[i]<=y[ilo]) ilo=i;
|
||||
if (y[i]>y[ihi]) {
|
||||
ise=ihi;
|
||||
ihi=i;
|
||||
} else if (y[i]>y[ise] && i!=ihi) ise=i;
|
||||
}
|
||||
|
||||
// Compute fractional range from highest to lowest point
|
||||
rtol=2.0*fabs(y[ihi]-y[ilo])/(fabs(y[ihi])+fabs(y[ilo])+TINY);
|
||||
|
||||
// Return if fractional tolerance is acceptable
|
||||
if (rtol<ftol)
|
||||
break;
|
||||
|
||||
if (nfunk>=NMAX) {
|
||||
printf("dsmin: NMAX exceeded!\n");
|
||||
return -1;
|
||||
}
|
||||
nfunk+=2;
|
||||
|
||||
// Reflect simplex
|
||||
ytry=dsmod(p,y,psum,n,func,ihi,-1.0);
|
||||
|
||||
if (ytry<=y[ilo]) // Goes right direction, extrapolate by factor 2
|
||||
ytry=dsmod(p,y,psum,n,func,ihi,2.0);
|
||||
else if (ytry>=y[ise]) { // 1D contraction
|
||||
ysave=y[ihi];
|
||||
ytry=dsmod(p,y,psum,n,func,ihi,0.5);
|
||||
if (ytry>=ysave) {
|
||||
for (i=0;i<=n;i++) {
|
||||
if (i!=ilo) {
|
||||
for (j=0;j<n;j++)
|
||||
p[i][j]=psum[j]=0.5*(p[i][j]+p[ilo][j]);
|
||||
y[i]=(*func)(psum);
|
||||
}
|
||||
}
|
||||
nfunk+=n;
|
||||
|
||||
psum=vector_sum(p,n);
|
||||
}
|
||||
} else --nfunk;
|
||||
}
|
||||
free(psum);
|
||||
|
||||
return nfunk;
|
||||
}
|
||||
|
||||
// Sum vectors
|
||||
double *vector_sum(double **p,int n)
|
||||
{
|
||||
int i,j;
|
||||
double sum,*psum;
|
||||
|
||||
psum=(double *) malloc(sizeof(double) * n);
|
||||
|
||||
for (i=0;i<n;i++) {
|
||||
sum=0.;
|
||||
for (j=0;j<=n;j++)
|
||||
sum+=p[j][i];
|
||||
psum[i]=sum;
|
||||
}
|
||||
|
||||
return psum;
|
||||
}
|
||||
|
||||
// Simplex modification
|
||||
double dsmod(double **p,double *y,double *psum,int n,double (*func)(double *),int ihi,double fac)
|
||||
{
|
||||
int i;
|
||||
double fac1,fac2,ytry,*ptry;
|
||||
|
||||
ptry=(double *) malloc(sizeof(double) * n);
|
||||
fac1=(1.0-fac)/(double) n;
|
||||
fac2=fac1-fac;
|
||||
|
||||
for (i=0;i<n;i++)
|
||||
ptry[i]=psum[i]*fac1-p[ihi][i]*fac2;
|
||||
ytry=(*func)(ptry);
|
||||
if (ytry<y[ihi]) {
|
||||
y[ihi]=ytry;
|
||||
for (i=0;i<n;i++) {
|
||||
psum[i] += ptry[i]-p[ihi][i];
|
||||
p[ihi][i]=ptry[i];
|
||||
}
|
||||
}
|
||||
|
||||
free(ptry);
|
||||
|
||||
return ytry;
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/* > satutl.c
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "sgdp4h.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
void fatal_error(const char *format, ...)
|
||||
{
|
||||
va_list arg_ptr;
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
fprintf(stderr, "\nDundee Satellite Lab fatal run-time error:\n");
|
||||
|
||||
va_start(arg_ptr, format);
|
||||
vfprintf(stderr, format, arg_ptr);
|
||||
va_end(arg_ptr);
|
||||
|
||||
fprintf(stderr, "\nNow terminating the program...\n");
|
||||
fflush(stderr);
|
||||
|
||||
exit(5);
|
||||
|
||||
}
|
||||
|
||||
/* ===================================================================== */
|
|
@ -0,0 +1,63 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LIM 81
|
||||
|
||||
int fgetline(FILE *,char *,int);
|
||||
void rtrim(char *);
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
char line[LIM];
|
||||
FILE *fitsfile;
|
||||
|
||||
// Usage
|
||||
if (argc<2) {
|
||||
printf("Usage: %s <fitsfile>\n",argv[0]);
|
||||
printf("\n\nOutputs the header of <fitsfile>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open file
|
||||
fitsfile=fopen(argv[1],"r");
|
||||
|
||||
// Loop over file and output
|
||||
while (fgetline(fitsfile,line,LIM)>0) {
|
||||
rtrim(line);
|
||||
printf("%s\n",line);
|
||||
if (strcmp(line,"END")==0) break;
|
||||
}
|
||||
|
||||
// Close file
|
||||
fclose(fitsfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
// Removes trailing blanks from string s
|
||||
void rtrim(char *s)
|
||||
{
|
||||
int i,j=0,n;
|
||||
|
||||
n=strlen(s);
|
||||
for (i=n;i>=0;i--)
|
||||
if (s[i]!='\0' && s[i]!='\n')
|
||||
if (!isspace(s[i]) && j==0) j=i;
|
||||
s[++j]='\0';
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "qfits.h"
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
int i;
|
||||
char keyword[FITS_LINESZ+1];
|
||||
char *value;
|
||||
|
||||
// Usage
|
||||
if (argc<3) {
|
||||
printf("Usage: %s <filename> [ext] <key1> <key2> etc.\n", argv[0]);
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
// Check this is indeed a FITS file
|
||||
if (is_fits_file(argv[1])!=1) {
|
||||
printf("%s is not a FITS file\n", argv[1]);
|
||||
return -1 ;
|
||||
}
|
||||
|
||||
// Extension header?
|
||||
if (atoi(argv[2])==0) {
|
||||
for (i=2;i<argc;i++)
|
||||
printf("%s ",qfits_query_hdr(argv[1], argv[i]));
|
||||
} else {
|
||||
for (i=3;i<argc;i++)
|
||||
printf("%s ",qfits_query_ext(argv[1], argv[i],atoi(argv[2])));
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
|
||||
return 0 ;
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
# Makefile: http://www.eng.hawaii.edu/Tutor/Make/
|
||||
|
||||
# Compiling flags
|
||||
CFLAGS = -O3 -Wno-unused-result
|
||||
|
||||
# Linking flags
|
||||
LFLAGS = -lm -lcpgplot -lpgplot -lX11 -fno-backslash -lpng -lqfits -lwcs_c -lgsl -lgslcblas -ljpeg -lexif
|
||||
|
||||
# Compilers
|
||||
CC = gcc
|
||||
F77 = gfortran
|
||||
|
||||
all:
|
||||
make satfit uk2iod rde2iod viewer residuals tleinfo satmap satorbit runsched fitskey fitsheader satid skymap addwcs reduce wcsfit plotfits pgm2fits
|
||||
|
||||
satfit: satfit.o sgdp4.o satutl.o deep.o ferror.o versafit.o dsmin.o simplex.o
|
||||
$(F77) -o satfit satfit.o sgdp4.o satutl.o deep.o ferror.o versafit.o dsmin.o simplex.o $(LFLAGS)
|
||||
|
||||
uk2iod: uk2iod.o
|
||||
$(CC) -o uk2iod uk2iod.o $(LFLAGS)
|
||||
|
||||
rde2iod: rde2iod.o
|
||||
$(CC) -o rde2iod rde2iod.o $(LFLAGS)
|
||||
|
||||
viewer: viewer.o
|
||||
$(CC) -o viewer viewer.o $(LFLAGS)
|
||||
|
||||
residuals: residuals.o sgdp4.o satutl.o deep.o ferror.o
|
||||
$(CC) -o residuals residuals.o sgdp4.o satutl.o deep.o ferror.o $(LFLAGS)
|
||||
|
||||
tleinfo: tleinfo.o sgdp4.o satutl.o deep.o ferror.o
|
||||
$(CC) -o tleinfo tleinfo.o sgdp4.o satutl.o deep.o ferror.o $(LFLAGS)
|
||||
|
||||
satmap: satmap.o sgdp4.o satutl.o deep.o ferror.o
|
||||
$(F77) -o satmap satmap.o sgdp4.o satutl.o deep.o ferror.o $(LFLAGS)
|
||||
|
||||
satorbit: satorbit.o sgdp4.o satutl.o deep.o ferror.o
|
||||
$(F77) -o satorbit satorbit.o sgdp4.o satutl.o deep.o ferror.o $(LFLAGS)
|
||||
|
||||
runsched: runsched.o
|
||||
$(CC) -o runsched runsched.o $(LFLAGS)
|
||||
|
||||
fitskey: fitskey.o
|
||||
$(CC) -o fitskey fitskey.o -lqfits
|
||||
|
||||
fitsheader: fitsheader.o
|
||||
$(CC) -o fitsheader fitsheader.o -lqfits
|
||||
|
||||
satid: satid.o sgdp4.o satutl.o deep.o ferror.o
|
||||
$(F77) -o satid satid.o sgdp4.o satutl.o deep.o ferror.o $(LFLAGS)
|
||||
|
||||
skymap: skymap.o sgdp4.o satutl.o deep.o ferror.o
|
||||
$(F77) -o skymap skymap.o sgdp4.o satutl.o deep.o ferror.o $(LFLAGS)
|
||||
|
||||
reduce: reduce.o
|
||||
$(F77) -o reduce reduce.o $(LFLAGS)
|
||||
|
||||
addwcs: addwcs.o
|
||||
$(F77) -o addwcs addwcs.o $(LFLAGS)
|
||||
|
||||
wcsfit: wcsfit.o
|
||||
$(F77) -o wcsfit wcsfit.o $(LFLAGS)
|
||||
|
||||
plotfits: plotfits.o
|
||||
$(F77) -o plotfits plotfits.o $(LFLAGS)
|
||||
|
||||
pgm2fits: pgm2fits.o
|
||||
$(F77) -o pgm2fits pgm2fits.o $(LFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f *~
|
|
@ -0,0 +1,594 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <qfits.h>
|
||||
#include <getopt.h>
|
||||
|
||||
struct image {
|
||||
int nx,ny;
|
||||
char timestamp[64];
|
||||
unsigned char *c;
|
||||
};
|
||||
struct fourframe {
|
||||
int nx,ny,nt,nlayer;
|
||||
char timestamp[64],observer[64];
|
||||
double mjd;
|
||||
float *z,*dt;
|
||||
int cospar;
|
||||
};
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
void write_fits(char *filename,struct fourframe ff);
|
||||
struct image read_pgm(char *filename,int *status);
|
||||
double nfd2mjd(char *date);
|
||||
double date2mjd(int year,int month,double day);
|
||||
void write_pgm(char *filename,struct fourframe ff);
|
||||
void mjd2date(double mjd,char *date);
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
printf("pgm2fits p:w:h:s:n:Dd:x:y:c:o:gm:t:r:\n\n");
|
||||
printf("-p image prefix\n");
|
||||
printf("-w image width in pixels\n");
|
||||
printf("-h image height in pixels\n");
|
||||
printf("-s number of first image to process\n");
|
||||
printf("-n number of images to process\n");
|
||||
printf("-D toggle for creating dark frame\n");
|
||||
printf("-d toggle for creating dark frame\n");
|
||||
printf("-d filename of dark frame to substract\n");
|
||||
printf("-m filename of mask frame to apply\n");
|
||||
printf("-x tracking rate in x (pix/s)\n");
|
||||
printf("-y tracking rate in y (pix/s)\n");
|
||||
printf("-c COSPAR [default 4553]\n");
|
||||
printf("-o observer [default \"Cees Bassa\"]\n");
|
||||
printf("-g toggle for guiding??\n");
|
||||
printf("-t time stamp of first image [YYYY-MM-DDTHH:MM:SS.SSS]\n");
|
||||
printf("-r frame rate (frames/s)\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i,j,k,l,m,k0=1,status,nt,darkout=0,darkin=0,track=0,maskin=0;
|
||||
int n,n0,di,dj,npix;
|
||||
struct image *img,drk,msk;
|
||||
struct fourframe ff;
|
||||
char filename[128],nfd[64];
|
||||
float s1,s2,z;
|
||||
float avg,std,max,cnt,*trk;
|
||||
int *wt;
|
||||
int arg=0;
|
||||
char *path,*darkfile,*maskfile;
|
||||
double mjd,mjd0=0.0;
|
||||
float dxdn=0.0,dydn=0.0,dx,dy;
|
||||
int guide=0,timereset=0;
|
||||
float framerate=25.0;
|
||||
char *env;
|
||||
|
||||
// Set defaults
|
||||
env=getenv("ST_COSPAR");
|
||||
ff.cospar=atoi(env);
|
||||
strcpy(ff.observer,"Cees Bassa");
|
||||
|
||||
// Decode options
|
||||
if (argc>1) {
|
||||
while ((arg=getopt(argc,argv,"p:w:h:s:n:Dd:x:y:c:o:gm:t:r:"))!=-1) {
|
||||
switch(arg) {
|
||||
case 'p':
|
||||
path=optarg;
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
guide=1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
ff.nx=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
ff.ny=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ff.cospar=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
strcpy(ff.observer,optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
k0=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
nt=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
darkout=1;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
darkin=1;
|
||||
darkfile=optarg;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
maskin=1;
|
||||
maskfile=optarg;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
dxdn=atof(optarg);
|
||||
track=1;
|
||||
break;
|
||||
|
||||
case 'y':
|
||||
dydn=atof(optarg);
|
||||
track=1;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
strcpy(nfd,optarg);
|
||||
mjd0=nfd2mjd(nfd);
|
||||
timereset=1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
framerate=atof(optarg);
|
||||
timereset=1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
usage();
|
||||
}
|
||||
|
||||
// Add layer
|
||||
if (track==1)
|
||||
ff.nlayer=5;
|
||||
else
|
||||
ff.nlayer=4;
|
||||
|
||||
// Allocate
|
||||
ff.z=(float *) malloc(ff.nlayer*sizeof(float)*ff.nx*ff.ny);
|
||||
ff.dt=(float *) malloc(sizeof(float)*nt);
|
||||
trk=(float *) malloc(sizeof(float)*ff.nx*ff.ny);
|
||||
wt=(int *) malloc(sizeof(float)*ff.nx*ff.ny);
|
||||
img=(struct image *) malloc(sizeof(struct image)*nt);
|
||||
|
||||
// Read dark file
|
||||
if (darkin==1)
|
||||
drk=read_pgm(darkfile,&status);
|
||||
|
||||
// Read mask file
|
||||
if (maskin==1)
|
||||
msk=read_pgm(maskfile,&status);
|
||||
|
||||
// Loop over files
|
||||
for (k=0,l=0;k<nt;k++) {
|
||||
sprintf(filename,"%s%06d.pgm",path,k+k0);
|
||||
img[l]=read_pgm(filename,&status);
|
||||
|
||||
// Reset time
|
||||
if (timereset==1) {
|
||||
mjd=mjd0+(double) (k+k0)/(86400.0*framerate);
|
||||
mjd2date(mjd,img[l].timestamp);
|
||||
}
|
||||
|
||||
ff.dt[l]=86400.0*(nfd2mjd(img[l].timestamp)-nfd2mjd(img[0].timestamp));
|
||||
if (status==0) {
|
||||
printf("Read %s\n",filename);
|
||||
l++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
ff.nt=l;
|
||||
strcpy(ff.timestamp,img[0].timestamp);
|
||||
ff.mjd=nfd2mjd(img[0].timestamp);
|
||||
|
||||
printf("Accumulating image statistics\n");
|
||||
// Loop over pixels
|
||||
for (i=0;i<ff.nx;i++) {
|
||||
for (j=0;j<ff.ny;j++) {
|
||||
n=i+ff.nx*j;
|
||||
|
||||
s1=0.0;
|
||||
s2=0.0;
|
||||
max=0.0;
|
||||
cnt=0.0;
|
||||
|
||||
// Loop over images
|
||||
for (k=0;k<ff.nt;k++) {
|
||||
if (darkin==0)
|
||||
z=(float) img[k].c[n];
|
||||
else if (darkin==1)
|
||||
z=(float) (img[k].c[n]-drk.c[n]);
|
||||
s1+=z;
|
||||
s2+=z*z;
|
||||
if (z>max) {
|
||||
max=z;
|
||||
cnt=(float) k;
|
||||
}
|
||||
}
|
||||
avg=s1/(float) ff.nt;
|
||||
std=sqrt((s2-s1*avg)/(float) (ff.nt-1));
|
||||
|
||||
// Reset masked pixels
|
||||
if (maskin==1 && msk.c[n]==0.0) {
|
||||
avg=0.0;
|
||||
std=0.0;
|
||||
max=0.0;
|
||||
cnt=128.0;
|
||||
}
|
||||
|
||||
for (m=0;m<ff.nlayer;m++) {
|
||||
l=i+(ff.ny-j-1)*ff.nx+m*ff.nx*ff.ny;
|
||||
if (m==0) ff.z[l]=avg;
|
||||
if (m==1) ff.z[l]=std;
|
||||
if (m==2) ff.z[l]=max;
|
||||
if (m==3) ff.z[l]=cnt;
|
||||
if (m==4) ff.z[l]=avg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create tracked layer
|
||||
if (track==1) {
|
||||
printf("Creating tracked layer\n");
|
||||
|
||||
// Set weights
|
||||
for (i=0;i<ff.nx*ff.ny;i++) {
|
||||
wt[i]=0;
|
||||
trk[i]=0.0;
|
||||
}
|
||||
|
||||
// Loop over frames
|
||||
for (l=0;l<ff.nt;l++) {
|
||||
// Offset
|
||||
dx=dxdn*(l-ff.nt/2);
|
||||
dy=dydn*(l-ff.nt/2);
|
||||
|
||||
// Integer offset
|
||||
di=(int) floor(dx+0.5);
|
||||
dj=(int) floor(dy+0.5);
|
||||
|
||||
// Set
|
||||
for (i=0;i<ff.nx;i++) {
|
||||
for (j=0;j<ff.ny;j++) {
|
||||
k=i+ff.nx*j;
|
||||
k0=i+di+ff.nx*(j+dj);
|
||||
if (i+di>0 && i+di<ff.nx && j+dj>0 && j+dj<ff.ny) {
|
||||
wt[k]+=1;
|
||||
trk[k]+=(float) img[l].c[k0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Save layer
|
||||
for (i=0;i<ff.nx;i++) {
|
||||
for (j=0;j<ff.ny;j++) {
|
||||
k=i+ff.nx*j;
|
||||
if (guide==0)
|
||||
l=i+(ff.ny-j-1)*ff.nx;
|
||||
else
|
||||
l=i+(ff.ny-j-1)*ff.nx+4*ff.nx*ff.ny;
|
||||
if (wt[k]>0)
|
||||
ff.z[l]=trk[k]/(float) wt[k];
|
||||
else
|
||||
ff.z[l]=trk[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write fits
|
||||
if (ff.timestamp!=NULL)
|
||||
sprintf(filename,"%s.fits",ff.timestamp);
|
||||
else
|
||||
strcpy(filename,"test.fits");
|
||||
write_fits(filename,ff);
|
||||
|
||||
// Write dark frame
|
||||
if (darkout==1)
|
||||
write_pgm("dark.pgm",ff);
|
||||
|
||||
// Free
|
||||
for (k=0;k<ff.nt;k++)
|
||||
free(img[k].c);
|
||||
free(ff.z);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read pgm file
|
||||
struct image read_pgm(char *filename,int *status)
|
||||
{
|
||||
int i;
|
||||
struct image img;
|
||||
FILE *file;
|
||||
char hbuf[64];
|
||||
|
||||
// Open file
|
||||
file=fopen(filename,"rb");
|
||||
if (file==NULL) {
|
||||
*status=1;
|
||||
return img;
|
||||
}
|
||||
|
||||
// Read PGM format
|
||||
fgetline(file,hbuf,64);
|
||||
if (strcmp(hbuf,"P5")!=0) {
|
||||
printf("Not a valid PGM file!\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
// Read timestamp/image size
|
||||
fgetline(file,hbuf,64);
|
||||
if (strstr(hbuf,"#")!=NULL) {
|
||||
strcpy(img.timestamp,hbuf+2);
|
||||
fgetline(file,hbuf,64);
|
||||
sscanf(hbuf,"%d %d",&img.nx,&img.ny);
|
||||
} else {
|
||||
strcpy(img.timestamp,"2012-01-01T00:00:00");
|
||||
sscanf(hbuf,"%d %d",&img.nx,&img.ny);
|
||||
}
|
||||
fgetline(file,hbuf,64);
|
||||
|
||||
// Allocate
|
||||
img.c=(unsigned char *) malloc(sizeof(unsigned char)*img.nx*img.ny);
|
||||
|
||||
// Read
|
||||
fread(img.c,1,img.nx*img.ny,file);
|
||||
|
||||
// Close file
|
||||
fclose(file);
|
||||
|
||||
*status=0;
|
||||
return img;
|
||||
}
|
||||
|
||||
// Get line
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim>0 && (c=fgetc(file))!=EOF && c!='\n')
|
||||
s[i++]=c;
|
||||
// if (c=='\n')
|
||||
// s[i++]=c;
|
||||
s[i]='\0';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// Write fits file
|
||||
void write_fits(char *filename,struct fourframe ff)
|
||||
{
|
||||
int i,j,k,l;
|
||||
float *fbuf;
|
||||
int *ibuf;
|
||||
qfitsdumper qd;
|
||||
qfits_header *qh;
|
||||
char key[FITS_LINESZ+1] ;
|
||||
char val[FITS_LINESZ+1] ;
|
||||
char com[FITS_LINESZ+1] ;
|
||||
char lin[FITS_LINESZ+1] ;
|
||||
FILE *file;
|
||||
|
||||
// Create FITS header
|
||||
qh=qfits_header_default();
|
||||
|
||||
// Add stuff
|
||||
qfits_header_add(qh,"BITPIX","-32"," ",NULL);
|
||||
// qfits_header_add(qh,"BITPIX","16"," ",NULL);
|
||||
qfits_header_add(qh,"NAXIS","3"," ",NULL);
|
||||
sprintf(val,"%i",ff.nx);
|
||||
qfits_header_add(qh,"NAXIS1",val," ",NULL);
|
||||
sprintf(val,"%i",ff.ny);
|
||||
qfits_header_add(qh,"NAXIS2",val," ",NULL);
|
||||
sprintf(val,"%i",ff.nlayer);
|
||||
qfits_header_add(qh,"NAXIS3",val," ",NULL);
|
||||
qfits_header_add(qh,"BSCALE","1.0"," ",NULL);
|
||||
qfits_header_add(qh,"BZERO","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"DATAMAX","255.0"," ",NULL);
|
||||
qfits_header_add(qh,"DATAMIN","0.0"," ",NULL);
|
||||
sprintf(val,"%s",ff.timestamp);
|
||||
qfits_header_add(qh,"DATE-OBS",val," ",NULL);
|
||||
// MJD-OBS
|
||||
sprintf(val,"%lf",ff.mjd);
|
||||
qfits_header_add(qh,"MJD-OBS",val," ",NULL);
|
||||
sprintf(val,"%f",ff.dt[ff.nt-1],ff.dt[0]);
|
||||
qfits_header_add(qh,"EXPTIME",val," ",NULL);
|
||||
sprintf(val,"%d",ff.nt);
|
||||
qfits_header_add(qh,"NFRAMES",val," ",NULL);
|
||||
|
||||
// Astrometry keywors
|
||||
sprintf(val,"%f",ff.nx/2.0);
|
||||
qfits_header_add(qh,"CRPIX1",val," ",NULL);
|
||||
sprintf(val,"%f",ff.ny/2.0);
|
||||
qfits_header_add(qh,"CRPIX2",val," ",NULL);
|
||||
qfits_header_add(qh,"CRVAL1","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CRVAL2","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CD1_1","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CD1_2","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CD2_1","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CD2_2","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CTYPE1","'RA---TAN'"," ",NULL);
|
||||
qfits_header_add(qh,"CTYPE2","'DEC--TAN'"," ",NULL);
|
||||
qfits_header_add(qh,"CUNIT1","'deg'"," ",NULL);
|
||||
qfits_header_add(qh,"CUNIT2","'deg'"," ",NULL);
|
||||
qfits_header_add(qh,"CRRES1","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"CRRES2","0.0"," ",NULL);
|
||||
qfits_header_add(qh,"EQUINOX","2000.0"," ",NULL);
|
||||
qfits_header_add(qh,"RADECSYS","ICRS"," ",NULL);
|
||||
sprintf(val,"%d",ff.cospar);
|
||||
qfits_header_add(qh,"COSPAR",val," ",NULL);
|
||||
sprintf(val,"'%s'",ff.observer);
|
||||
qfits_header_add(qh,"OBSERVER",val," ",NULL);
|
||||
|
||||
// Add timestamps
|
||||
for (k=0;k<ff.nt;k++) {
|
||||
sprintf(key,"DT%04d",k);
|
||||
sprintf(val,"%f",ff.dt[k]);
|
||||
qfits_header_add(qh,key,val," ",NULL);
|
||||
}
|
||||
|
||||
// Dummy keywords
|
||||
for (k=0;k<10;k++) {
|
||||
sprintf(key,"DUMY%03d",k);
|
||||
qfits_header_add(qh,key,"0.0"," ",NULL);
|
||||
}
|
||||
|
||||
// Dump fitsheader
|
||||
// qfits_header_dump(qh,stdout);
|
||||
|
||||
// Dump to file
|
||||
file=fopen(filename,"w");
|
||||
qfits_header_dump(qh,file);
|
||||
fclose(file);
|
||||
|
||||
|
||||
// Fill buffer
|
||||
fbuf=malloc(ff.nlayer*ff.nx*ff.ny*sizeof(float));
|
||||
// ibuf=malloc(4*ff.nx*ff.ny*sizeof(int));
|
||||
for (i=0,l=0;i<ff.nx;i++) {
|
||||
for (j=ff.ny-1;j>=0;j--) {
|
||||
for (k=0;k<ff.nlayer;k++) {
|
||||
fbuf[l]=ff.z[l];
|
||||
// ibuf[l]=(int) ff.z[l];
|
||||
|
||||
l++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set parameters
|
||||
qd.filename=filename;
|
||||
qd.npix=ff.nlayer*ff.nx*ff.ny;
|
||||
qd.ptype=PTYPE_FLOAT;
|
||||
// qd.ptype=PTYPE_INT;
|
||||
qd.fbuf=fbuf;
|
||||
// qd.ibuf=ibuf;
|
||||
qd.out_ptype=-32;
|
||||
// qd.out_ptype=BPP_16_SIGNED;
|
||||
|
||||
// Dump
|
||||
qfits_pixdump(&qd);
|
||||
|
||||
free(fbuf);
|
||||
// free(ibuf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute Julian Day from Date
|
||||
double date2mjd(int year,int month,double day)
|
||||
{
|
||||
int a,b;
|
||||
double jd;
|
||||
|
||||
if (month<3) {
|
||||
year--;
|
||||
month+=12;
|
||||
}
|
||||
|
||||
a=floor(year/100.);
|
||||
b=2.-a+floor(a/4.);
|
||||
|
||||
if (year<1582) b=0;
|
||||
if (year==1582 && month<10) b=0;
|
||||
if (year==1852 && month==10 && day<=4) b=0;
|
||||
|
||||
jd=floor(365.25*(year+4716))+floor(30.6001*(month+1))+day+b-1524.5;
|
||||
|
||||
return jd-2400000.5;
|
||||
}
|
||||
|
||||
// nfd2mjd
|
||||
double nfd2mjd(char *date)
|
||||
{
|
||||
int year,month,day,hour,min;
|
||||
double mjd,dday;
|
||||
float sec;
|
||||
|
||||
sscanf(date,"%04d-%02d-%02dT%02d:%02d:%f",&year,&month,&day,&hour,&min,&sec);
|
||||
dday=day+hour/24.0+min/1440.0+sec/86400.0;
|
||||
mjd=date2mjd(year,month,dday);
|
||||
|
||||
return mjd;
|
||||
}
|
||||
|
||||
// Write pgm file
|
||||
void write_pgm(char *filename,struct fourframe ff)
|
||||
{
|
||||
int i,j,k;
|
||||
FILE *file;
|
||||
|
||||
file=fopen(filename,"w");
|
||||
fprintf(file,"P5\n# 2013-01-01T00:00:00\n%d %d\n255\n",ff.nx,ff.ny);
|
||||
for (j=0;j<ff.ny;j++) {
|
||||
for (i=0;i<ff.nx;i++) {
|
||||
k=i+(ff.ny-j-1)*ff.nx;
|
||||
fprintf(file,"%c",(char) ff.z[k]);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute Date from Julian Day
|
||||
void mjd2date(double mjd,char *date)
|
||||
{
|
||||
double f,jd,dday;
|
||||
int z,alpha,a,b,c,d,e;
|
||||
int year,month,day,hour,min;
|
||||
float sec,x;
|
||||
|
||||
jd=mjd+2400000.5;
|
||||
jd+=0.5;
|
||||
|
||||
z=floor(jd);
|
||||
f=fmod(jd,1.);
|
||||
|
||||
if (z<2299161)
|
||||
a=z;
|
||||
else {
|
||||
alpha=floor((z-1867216.25)/36524.25);
|
||||
a=z+1+alpha-floor(alpha/4.);
|
||||
}
|
||||
b=a+1524;
|
||||
c=floor((b-122.1)/365.25);
|
||||
d=floor(365.25*c);
|
||||
e=floor((b-d)/30.6001);
|
||||
|
||||
dday=b-d-floor(30.6001*e)+f;
|
||||
if (e<14)
|
||||
month=e-1;
|
||||
else
|
||||
month=e-13;
|
||||
|
||||
if (month>2)
|
||||
year=c-4716;
|
||||
else
|
||||
year=c-4715;
|
||||
|
||||
day=(int) floor(dday);
|
||||
x=24.0*(dday-day);
|
||||
x=3600.*fabs(x);
|
||||
sec=fmod(x,60.);
|
||||
x=(x-sec)/60.;
|
||||
min=fmod(x,60.);
|
||||
x=(x-min)/60.;
|
||||
hour=x;
|
||||
|
||||
sprintf(date,"%04d-%02d-%02dT%02d:%02d:%06.3f",year,month,day,hour,min,sec);
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,726 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "cel.h"
|
||||
#include "cpgplot.h"
|
||||
#include "qfits.h"
|
||||
#include <gsl/gsl_multifit.h>
|
||||
|
||||
#define LIM 256
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
#define NMAX 4096
|
||||
|
||||
struct star {
|
||||
double ra,de;
|
||||
float pmra,pmde;
|
||||
float mag;
|
||||
};
|
||||
struct image {
|
||||
int naxis1,naxis2,naxis3;
|
||||
float *z;
|
||||
float zmin,zmax;
|
||||
double ra0,de0;
|
||||
float x0,y0;
|
||||
float a[3],b[3];
|
||||
double mjd;
|
||||
} img;
|
||||
struct catalog {
|
||||
int n;
|
||||
float x[NMAX],y[NMAX],mag[NMAX];
|
||||
double ra[NMAX],de[NMAX],rx[NMAX],ry[NMAX];
|
||||
int select[NMAX];
|
||||
};
|
||||
struct map {
|
||||
double lat,lng;
|
||||
float alt;
|
||||
int site_id;
|
||||
char observer[32];
|
||||
} m;
|
||||
|
||||
struct image read_fits(char *filename,int pnum);
|
||||
int fgetline(FILE *,char *,int);
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y);
|
||||
void reverse(double,double,double,double,double *,double *);
|
||||
void lfit2d(float *x,float *y,float *z,int n,float *a);
|
||||
struct catalog read_pixel_catalog(char *filename);
|
||||
double gmst(double mjd);
|
||||
double modulo(double x,double y);
|
||||
void precess(double mjd0,double ra0,double de0,double mjd,double *ra,double *de);
|
||||
double sex2dec(char *s);
|
||||
|
||||
// Read astrometric catalog
|
||||
struct catalog read_astrometric_catalog(char *filename,float mmin,float sx,float sy,float angle)
|
||||
{
|
||||
int i=0;
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
struct catalog c;
|
||||
double rx,ry,x,y,ra,de;
|
||||
struct star s;
|
||||
double d,dx,dy;
|
||||
double mjd0=51544.5;
|
||||
|
||||
file=fopen(filename,"rb");
|
||||
if (file==NULL) {
|
||||
fprintf(stderr,"%s not found!\n",filename);
|
||||
exit(0);
|
||||
}
|
||||
while (!feof(file)) {
|
||||
fread(&s,sizeof(struct star),1,file);
|
||||
if (s.mag>mmin)
|
||||
continue;
|
||||
precess(mjd0,s.ra,s.de,img.mjd,&ra,&de);
|
||||
forward(img.ra0,img.de0,ra,de,&rx,&ry);
|
||||
x=img.x0+1.0/sx*(cos(angle*D2R)*rx+sin(angle*D2R)*ry);
|
||||
y=img.y0+1.0/sy*(-sin(angle*D2R)*rx+cos(angle*D2R)*ry);
|
||||
/*
|
||||
} else if (t.state==1) {
|
||||
dx=rx-t.a[0];
|
||||
dy=ry-t.b[0];
|
||||
d=t.a[1]*t.b[2]-t.a[2]*t.b[1];
|
||||
x=(t.b[2]*dx-t.a[2]*dy)/d;
|
||||
y=(t.a[1]*dy-t.b[1]*dx)/d;
|
||||
}
|
||||
*/
|
||||
if (x>0.0 && x<img.naxis1 && y>0.0 && y<img.naxis2) {
|
||||
c.x[i]=x;
|
||||
c.y[i]=y;
|
||||
c.rx[i]=rx;
|
||||
c.ry[i]=ry;
|
||||
c.ra[i]=s.ra;
|
||||
c.de[i]=s.de;
|
||||
c.mag[i]=s.mag;
|
||||
c.select[i]=0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
c.n=i;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Read astrometric catalog
|
||||
struct catalog reread_astrometric_catalog(char *filename,float mmin)
|
||||
{
|
||||
int i=0;
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
struct catalog c;
|
||||
double rx,ry,x,y;
|
||||
struct star s;
|
||||
double d,dx,dy,ra,de;
|
||||
double mjd0=51544.5;
|
||||
|
||||
file=fopen(filename,"rb");
|
||||
while (!feof(file)) {
|
||||
fread(&s,sizeof(struct star),1,file);
|
||||
if (s.mag>mmin)
|
||||
continue;
|
||||
precess(mjd0,s.ra,s.de,img.mjd,&ra,&de);
|
||||
forward(img.ra0,img.de0,ra,de,&rx,&ry);
|
||||
dx=rx-img.a[0];
|
||||
dy=ry-img.b[0];
|
||||
d=img.a[1]*img.b[2]-img.a[2]*img.b[1];
|
||||
x=(img.b[2]*dx-img.a[2]*dy)/d+img.x0;
|
||||
y=(img.a[1]*dy-img.b[1]*dx)/d+img.y0;
|
||||
if (x>0.0 && x<img.naxis1 && y>0.0 && y<img.naxis2) {
|
||||
c.x[i]=x;
|
||||
c.y[i]=y;
|
||||
c.rx[i]=rx;
|
||||
c.ry[i]=ry;
|
||||
c.ra[i]=s.ra;
|
||||
c.de[i]=s.de;
|
||||
c.mag[i]=s.mag;
|
||||
c.select[i]=0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
c.n=i;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
int select_nearest(struct catalog c,float x,float y)
|
||||
{
|
||||
int i,imin;
|
||||
float r,rmin;
|
||||
|
||||
for (i=0;i<c.n;i++) {
|
||||
r=sqrt(pow(x-c.x[i],2)+pow(y-c.y[i],2));
|
||||
if (i==0 || r<rmin) {
|
||||
imin=i;
|
||||
rmin=r;
|
||||
}
|
||||
}
|
||||
|
||||
return imin;
|
||||
}
|
||||
|
||||
// Fit transformation
|
||||
void fit_transformation(struct catalog cat,struct catalog ast,int nselect)
|
||||
{
|
||||
int i,j;
|
||||
float *x,*y,*rx,*ry;
|
||||
|
||||
x=(float *) malloc(sizeof(float)*nselect);
|
||||
y=(float *) malloc(sizeof(float)*nselect);
|
||||
rx=(float *) malloc(sizeof(float)*nselect);
|
||||
ry=(float *) malloc(sizeof(float)*nselect);
|
||||
|
||||
for (i=0;i<nselect;i++) {
|
||||
for (j=0;j<cat.n;j++) {
|
||||
if (cat.select[j]==i+1) {
|
||||
x[i]=cat.x[j]-img.x0;
|
||||
y[i]=cat.y[j]-img.y0;
|
||||
}
|
||||
}
|
||||
for (j=0;j<ast.n;j++) {
|
||||
if (ast.select[j]==i+1) {
|
||||
rx[i]=ast.rx[j];
|
||||
ry[i]=ast.ry[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lfit2d(x,y,rx,nselect,img.a);
|
||||
lfit2d(x,y,ry,nselect,img.b);
|
||||
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int match_catalogs(struct catalog *cat,struct catalog *ast,float rmax)
|
||||
{
|
||||
int i,j,jmin,n,flag=0;
|
||||
float r,rmin;
|
||||
FILE *file;
|
||||
|
||||
// Reset
|
||||
for (i=0;i<cat->n;i++)
|
||||
cat->select[i]=0;
|
||||
for (i=0;i<ast->n;i++)
|
||||
ast->select[i]=0;
|
||||
|
||||
file=fopen("out.dat","w");
|
||||
for (i=0,n=0;i<cat->n;i++) {
|
||||
for (j=0,flag=0;j<ast->n;j++) {
|
||||
if (ast->select[j]!=0)
|
||||
continue;
|
||||
r=sqrt(pow(cat->x[i]-ast->x[j],2)+pow(cat->y[i]-ast->y[j],2));
|
||||
if (flag==0 || r<rmin) {
|
||||
rmin=r;
|
||||
jmin=j;
|
||||
flag=1;
|
||||
}
|
||||
}
|
||||
if (rmin<rmax) {
|
||||
fprintf(file,"%10.4f %10.4f %10.6f %10.6f\n",cat->x[i]-img.x0,cat->y[i]-img.y0,ast->ra[jmin],ast->de[jmin]);
|
||||
cat->select[i]=n+1;
|
||||
ast->select[jmin]=n+1;
|
||||
n++;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
printf("%d stars matched\n",n);
|
||||
return n;
|
||||
}
|
||||
|
||||
// Get observing site
|
||||
void get_site(int site_id)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
int id;
|
||||
double lat,lng;
|
||||
float alt;
|
||||
char abbrev[3],observer[64],filename[LIM],*env;
|
||||
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(filename,"%s/data/sites.txt",env);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
printf("File with site information not found!\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line,LIM,file)!=NULL) {
|
||||
// Skip
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
|
||||
// Strip newline
|
||||
line[strlen(line)-1]='\0';
|
||||
|
||||
// Read data
|
||||
sscanf(line,"%4d %2s %lf %lf %f",
|
||||
&id,abbrev,&lat,&lng,&alt);
|
||||
strcpy(observer,line+38);
|
||||
|
||||
// Change to km
|
||||
alt/=1000.0;
|
||||
|
||||
if (id==site_id) {
|
||||
m.lat=lat;
|
||||
m.lng=lng;
|
||||
m.alt=alt;
|
||||
m.site_id=id;
|
||||
strcpy(m.observer,observer);
|
||||
}
|
||||
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
float tr[]={-0.5,1.0,0.0,-0.5,0.0,1.0};
|
||||
float heat_l[] = {0.0, 0.2, 0.4, 0.6, 1.0};
|
||||
float heat_r[] = {0.0, 0.5, 1.0, 1.0, 1.0};
|
||||
float heat_g[] = {0.0, 0.0, 0.5, 1.0, 1.0};
|
||||
float heat_b[] = {0.0, 0.0, 0.0, 0.3, 1.0};
|
||||
float x,y,r,rmin=1.0,rmax=10.0,mmin=5.0,mmax=10.0;
|
||||
struct catalog cat,ast;
|
||||
char c;
|
||||
int redraw=1,click=0,nselect=0;
|
||||
char filename[128],sra[20],sde[20];
|
||||
float h,q,s=0.0,mag=9;
|
||||
FILE *file;
|
||||
char *env,starfile[128];
|
||||
|
||||
// Environment variables
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(starfile,"%s/data/tycho2.dat",env);
|
||||
|
||||
// Geographic position
|
||||
env=getenv("ST_COSPAR");
|
||||
get_site(atoi(env));
|
||||
|
||||
|
||||
// Read image
|
||||
img=read_fits(argv[1],0);
|
||||
sprintf(filename,"%s.cat",argv[1]);
|
||||
|
||||
printf("Image read\n");
|
||||
|
||||
// Initial transformation
|
||||
if (argc==7) {
|
||||
s=atof(argv[2]);
|
||||
img.ra0=atof(argv[3]);
|
||||
img.de0=atof(argv[4]);
|
||||
q=atof(argv[5]);
|
||||
mag=atof(argv[6]);
|
||||
} else {
|
||||
file=fopen("position.txt","r");
|
||||
if (file==NULL) {
|
||||
fprintf(stderr,"No position file found\n");
|
||||
return 0;
|
||||
}
|
||||
fscanf(file,"%s %s",sra,sde);
|
||||
fclose(file);
|
||||
|
||||
// Get parameters
|
||||
img.ra0=15.0*sex2dec(sra);
|
||||
img.de0=sex2dec(sde);
|
||||
|
||||
// Hour angle
|
||||
h=gmst(img.mjd)+m.lng-img.ra0;
|
||||
q=atan2(sin(h*D2R),(tan(m.lat*D2R)*cos(img.de0*D2R)-sin(img.de0*D2R)*cos(h*D2R)))*R2D;
|
||||
printf("Hour angle: %.3f deg, parallactic angle: %.3f deg\n",h,q);
|
||||
}
|
||||
img.x0=0.5*(float) img.naxis1;
|
||||
img.y0=0.5*(float) img.naxis2;
|
||||
|
||||
// Read catalogs
|
||||
cat=read_pixel_catalog(filename);
|
||||
if (s==0.0)
|
||||
ast=read_astrometric_catalog(starfile,mag,-36.15,33.22,-q);
|
||||
else
|
||||
ast=read_astrometric_catalog(starfile,mag,-s,s,-q);
|
||||
|
||||
// Plot image
|
||||
cpgopen("/xs");
|
||||
cpgwnad(0.0,img.naxis1,0.0,img.naxis2);
|
||||
cpgsfs(2);
|
||||
cpgctab (heat_l,heat_r,heat_g,heat_b,5,1.0,0.5);
|
||||
|
||||
// For ever loop
|
||||
for (;;) {
|
||||
if (redraw==1) {
|
||||
cpgimag(img.z,img.naxis1,img.naxis2,1,img.naxis1,1,img.naxis2,img.zmin,img.zmax,tr);
|
||||
cpgbox("BCTSNI",0.,0,"BCTSNI",0.,0);
|
||||
|
||||
// Plot catalogs
|
||||
cpgsci(3);
|
||||
for (i=0;i<cat.n;i++) {
|
||||
if (cat.select[i]!=0)
|
||||
cpgpt1(cat.x[i],cat.y[i],6);
|
||||
else
|
||||
cpgpt1(cat.x[i],cat.y[i],4);
|
||||
}
|
||||
cpgsci(4);
|
||||
for (i=0;i<ast.n;i++) {
|
||||
r=rmax-(rmax-rmin)*(ast.mag[i]-mmin)/(mmax-mmin);
|
||||
|
||||
// Upscale for image size
|
||||
r*=img.naxis1/752.0;
|
||||
if (ast.select[i]!=0)
|
||||
cpgpt1(ast.x[i],ast.y[i],6);
|
||||
cpgcirc(ast.x[i],ast.y[i],r);
|
||||
}
|
||||
cpgsci(1);
|
||||
redraw=0;
|
||||
}
|
||||
|
||||
cpgcurs(&x,&y,&c);
|
||||
|
||||
// Quit
|
||||
if (c=='q')
|
||||
break;
|
||||
|
||||
// Fit
|
||||
if (c=='f' && nselect>=3) {
|
||||
fit_transformation(cat,ast,nselect);
|
||||
ast=reread_astrometric_catalog(starfile,mag+1);
|
||||
redraw=1;
|
||||
}
|
||||
|
||||
// Reread
|
||||
if (c=='r') {
|
||||
ast=reread_astrometric_catalog(starfile,mag+1);
|
||||
redraw=1;
|
||||
}
|
||||
|
||||
// Select pixel catalog
|
||||
if (c=='a' && click==0) {
|
||||
i=select_nearest(cat,x,y);
|
||||
cat.select[i]=nselect+1;
|
||||
redraw=1;
|
||||
click=1;
|
||||
}
|
||||
|
||||
// Select catalog
|
||||
if (c=='b' && click==1) {
|
||||
i=select_nearest(ast,x,y);
|
||||
ast.select[i]=nselect+1;
|
||||
redraw=1;
|
||||
click=0;
|
||||
nselect++;
|
||||
}
|
||||
|
||||
// Print
|
||||
if (c=='p') {
|
||||
|
||||
}
|
||||
|
||||
// Match catalogs
|
||||
if (c=='m') {
|
||||
nselect=match_catalogs(&cat,&ast,10.0);
|
||||
redraw=1;
|
||||
}
|
||||
}
|
||||
cpgend();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read fits image
|
||||
struct image read_fits(char *filename,int pnum)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1] ;
|
||||
struct image img;
|
||||
float s1,s2,avg,std;
|
||||
|
||||
// Set plane
|
||||
ql.xtnum = 0;
|
||||
ql.pnum = pnum;
|
||||
|
||||
// Set loadtype
|
||||
ql.ptype = PTYPE_FLOAT;
|
||||
|
||||
// Set filename
|
||||
ql.filename=filename;
|
||||
|
||||
// Image size
|
||||
img.naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
img.naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
img.mjd=atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
|
||||
// Initialize load
|
||||
if (qfitsloader_init(&ql) != 0)
|
||||
printf("Error initializing data loading\n");
|
||||
|
||||
// Test load
|
||||
if (qfits_loadpix(&ql) != 0)
|
||||
printf("Error loading actual data\n");
|
||||
|
||||
// Allocate image memory
|
||||
img.z=(float *) malloc(sizeof(float) * img.naxis1*img.naxis2);
|
||||
|
||||
// Fill z array
|
||||
for (i=0,l=0,m=0;i<img.naxis1;i++) {
|
||||
for (j=0;j<img.naxis2;j++) {
|
||||
img.z[l]=ql.fbuf[l];
|
||||
l++;
|
||||
}
|
||||
}
|
||||
|
||||
// Get levels
|
||||
for (i=0,s1=0.0,s2=0.0;i<img.naxis1*img.naxis2;i++) {
|
||||
s1+=img.z[i];
|
||||
s2+=img.z[i]*img.z[i];
|
||||
}
|
||||
avg=s1/(float) (img.naxis1*img.naxis2);
|
||||
std=sqrt(s2/(float) (img.naxis1*img.naxis2)-avg*avg);
|
||||
printf("%f %f\n",avg,std);
|
||||
img.zmin=avg-4.0*std;
|
||||
img.zmax=avg+6.0*std;
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
// Get a x and y from a RA and Decl
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="STG";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celfwd(pcode,ra,de,&cel,&phi,&theta,&prj,x,y)) {
|
||||
printf("Error in Projection (celfwd)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
*x *=3600.;
|
||||
*y *=3600.;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Linear 2D fit
|
||||
void lfit2d(float *x,float *y,float *z,int n,float *a)
|
||||
{
|
||||
int i;
|
||||
double chisq;
|
||||
gsl_matrix *X,*cov;
|
||||
gsl_vector *yy,*w,*c;
|
||||
|
||||
X=gsl_matrix_alloc(n,3);
|
||||
yy=gsl_vector_alloc(n);
|
||||
w=gsl_vector_alloc(n);
|
||||
|
||||
c=gsl_vector_alloc(3);
|
||||
cov=gsl_matrix_alloc(3,3);
|
||||
|
||||
// Fill matrices
|
||||
for(i=0;i<n;i++) {
|
||||
gsl_matrix_set(X,i,0,1.0);
|
||||
gsl_matrix_set(X,i,1,x[i]);
|
||||
gsl_matrix_set(X,i,2,y[i]);
|
||||
|
||||
gsl_vector_set(yy,i,z[i]);
|
||||
gsl_vector_set(w,i,1.0);
|
||||
}
|
||||
|
||||
// Do fit
|
||||
gsl_multifit_linear_workspace *work=gsl_multifit_linear_alloc(n,3);
|
||||
gsl_multifit_wlinear(X,w,yy,c,cov,&chisq,work);
|
||||
gsl_multifit_linear_free(work);
|
||||
|
||||
// Save parameters
|
||||
for (i=0;i<3;i++)
|
||||
a[i]=gsl_vector_get(c,(i));
|
||||
|
||||
gsl_matrix_free(X);
|
||||
gsl_vector_free(yy);
|
||||
gsl_vector_free(w);
|
||||
gsl_vector_free(c);
|
||||
gsl_matrix_free(cov);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a RA and Decl from x and y
|
||||
void reverse(double ra0,double de0,double x,double y,double *ra,double *de)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="STG";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
x/=3600.;
|
||||
y/=3600.;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celrev(pcode,x,y,&prj,&phi,&theta,&cel,ra,de)) {
|
||||
printf("Error in Projection (celrev)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Read pixel catalog
|
||||
struct catalog read_pixel_catalog(char *filename)
|
||||
{
|
||||
int i=0;
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
struct catalog c;
|
||||
|
||||
// Read catalog
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
fprintf(stderr,"%s not found!\n",filename);
|
||||
exit(0);
|
||||
}
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
sscanf(line,"%f %f %f",&c.x[i],&c.y[i],&c.mag[i]);
|
||||
c.select[i]=0;
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
c.n=i;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double gmst(double mjd)
|
||||
{
|
||||
double t,gmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
gmst=modulo(280.46061837+360.98564736629*(mjd-51544.5)+t*t*(0.000387933-t/38710000),360.0);
|
||||
|
||||
return gmst;
|
||||
}
|
||||
|
||||
// Return x modulo y [0,y)
|
||||
double modulo(double x,double y)
|
||||
{
|
||||
x=fmod(x,y);
|
||||
if (x<0.0) x+=y;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Precess a celestial position
|
||||
void precess(double mjd0,double ra0,double de0,double mjd,double *ra,double *de)
|
||||
{
|
||||
double t0,t;
|
||||
double zeta,z,theta;
|
||||
double a,b,c;
|
||||
|
||||
// Angles in radians
|
||||
ra0*=D2R;
|
||||
de0*=D2R;
|
||||
|
||||
// Time in centuries
|
||||
t0=(mjd0-51544.5)/36525.0;
|
||||
t=(mjd-mjd0)/36525.0;
|
||||
|
||||
// Precession angles
|
||||
zeta=(2306.2181+1.39656*t0-0.000139*t0*t0)*t;
|
||||
zeta+=(0.30188-0.000344*t0)*t*t+0.017998*t*t*t;
|
||||
zeta*=D2R/3600.0;
|
||||
z=(2306.2181+1.39656*t0-0.000139*t0*t0)*t;
|
||||
z+=(1.09468+0.000066*t0)*t*t+0.018203*t*t*t;
|
||||
z*=D2R/3600.0;
|
||||
theta=(2004.3109-0.85330*t0-0.000217*t0*t0)*t;
|
||||
theta+=-(0.42665+0.000217*t0)*t*t-0.041833*t*t*t;
|
||||
theta*=D2R/3600.0;
|
||||
|
||||
a=cos(de0)*sin(ra0+zeta);
|
||||
b=cos(theta)*cos(de0)*cos(ra0+zeta)-sin(theta)*sin(de0);
|
||||
c=sin(theta)*cos(de0)*cos(ra0+zeta)+cos(theta)*sin(de0);
|
||||
|
||||
*ra=(atan2(a,b)+z)*R2D;
|
||||
*de=asin(c)*R2D;
|
||||
|
||||
if (*ra<360.0)
|
||||
*ra+=360.0;
|
||||
if (*ra>360.0)
|
||||
*ra-=360.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert Sexagesimal into Decimal
|
||||
double sex2dec(char *s)
|
||||
{
|
||||
double x;
|
||||
float deg,min,sec;
|
||||
char t[LIM];
|
||||
|
||||
strcpy(t,s);
|
||||
|
||||
deg=fabs(atof(strtok(t," :")));
|
||||
min=fabs(atof(strtok(NULL," :")));
|
||||
sec=fabs(atof(strtok(NULL," :")));
|
||||
|
||||
x=(double) deg+(double) min/60.+(double) sec/3600.;
|
||||
if (s[0]=='-') x= -x;
|
||||
|
||||
return x;
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define LIM 128
|
||||
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
int find_satno(char *desig0)
|
||||
{
|
||||
FILE *file;
|
||||
int satno=99999,status;
|
||||
char desig[16];
|
||||
char *env,filename[LIM];
|
||||
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(filename,"%s/data/desig.txt",env);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
fprintf(stderr,"Designation file not found!\n");
|
||||
exit(0);
|
||||
}
|
||||
while (!feof(file)) {
|
||||
status=fscanf(file,"%d %s",&satno,desig);
|
||||
if (strcmp(desig,desig0)==0)
|
||||
break;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return satno;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
int intidy,intido,piece,site,year,month,day,hour,min,sec,fsec,satno;
|
||||
char desig[16],pdesig[16];
|
||||
int format,epoch,dummy,icsec;
|
||||
float csec,cang;
|
||||
int rah,ram,rafm,ded,dem,defm;
|
||||
float tm,tx,am,ax;
|
||||
char sign;
|
||||
int lineno=0;
|
||||
|
||||
file=fopen(argv[1],"r");
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
if (strncmp(line,"2420",4)==0 && lineno==0) {
|
||||
lineno++;
|
||||
sscanf(line,"%04d %02d%02d",&site,&year,&month);
|
||||
sscanf(line+12,"%1d%1d%1d %3d%1d",&icsec,&dummy,&format,&dummy,&epoch);
|
||||
|
||||
csec=0.1*icsec;
|
||||
cang=dummy;
|
||||
|
||||
// Year switch
|
||||
if (year>50)
|
||||
year+=1900;
|
||||
else
|
||||
year+=2000;
|
||||
|
||||
// Time accuracy
|
||||
tx=floor(log10(csec))+8;
|
||||
tm=floor(csec/pow(10.0,tx-8));
|
||||
|
||||
// angle accuracy
|
||||
ax=floor(log10(cang))+8;
|
||||
am=floor(cang/pow(10.0,ax-8));
|
||||
|
||||
if (ax>9.0) {
|
||||
ax=9.0;
|
||||
am=9.0;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
if (strlen(line)<5 && lineno==1) {
|
||||
sscanf(line,"%d",&day);
|
||||
if (day==999)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip wrong lines
|
||||
if (!isdigit(line[0]))
|
||||
continue;
|
||||
// Skip short lines
|
||||
if (strlen(line)<31)
|
||||
continue;
|
||||
|
||||
// Scan line
|
||||
sscanf(line,"%02d%03d%02d",&intidy,&intido,&piece);
|
||||
sscanf(line+8,"%02d%02d%02d.%02d",&hour,&min,&sec,&fsec);
|
||||
sscanf(line+18,"%02d%02d%d",&rah,&ram,&rafm);
|
||||
sscanf(line+24,"%c%02d%02d%d",&sign,&ded,&dem,&defm);
|
||||
fsec*=10.0;
|
||||
// Format designation
|
||||
if (piece<26) {
|
||||
sprintf(desig,"%02d %03d%c",intidy,intido,piece+'A'-1);
|
||||
sprintf(pdesig,"%02d%03d%c",intidy,intido,piece+'A'-1);
|
||||
} else {
|
||||
fprintf(stderr,"Failed to understand designation!\n");
|
||||
fprintf(stderr,"%s\n",line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Test data format
|
||||
if (format!=1) {
|
||||
fprintf(stderr,"Angle format %d not implemented!\n",format);
|
||||
fprintf(stderr,"%s\n",line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fractional RA
|
||||
if (rafm<10)
|
||||
rafm*=100;
|
||||
else if (rafm<100)
|
||||
rafm*=10;
|
||||
|
||||
// Fractional DE
|
||||
if (defm<10)
|
||||
defm*=10;
|
||||
else if (defm<100)
|
||||
defm*=1;
|
||||
|
||||
// Get satellite number
|
||||
satno=find_satno(pdesig);
|
||||
|
||||
// Format IOD line
|
||||
printf("%05d %s %04d G %04d%02d%02d%02d%02d%02d%03d %1.0f%1.0f %d%d ",satno,desig,site,year,month,day,hour,min,sec,fsec,tm,tx,format,epoch);
|
||||
printf("%02d%02d%03d%c%02d%02d%02d %1.0f%1.0f\n",rah,ram,rafm,sign,ded,dem,defm,am,ax);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
|
@ -0,0 +1,526 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "cel.h"
|
||||
#include "sgdp4h.h"
|
||||
#include <getopt.h>
|
||||
|
||||
#define LIM 80
|
||||
#define NMAX 256
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
#define XKMPER 6378.135 // Earth radius in km
|
||||
#define XKMPAU 149597879.691 // AU in km
|
||||
#define FLAT (1.0/298.257)
|
||||
|
||||
long Isat=0;
|
||||
long Isatsel=0;
|
||||
extern double SGDP4_jd0;
|
||||
|
||||
struct point {
|
||||
int flag,satno;
|
||||
double mjd,ra,de;
|
||||
float st,sr;
|
||||
char iod_line[LIM];
|
||||
xyz_t obspos;
|
||||
};
|
||||
struct site {
|
||||
int id;
|
||||
double lng,lat;
|
||||
float alt;
|
||||
char observer[64];
|
||||
};
|
||||
struct data {
|
||||
int n;
|
||||
struct point *p;
|
||||
} ;
|
||||
struct point decode_iod_observation(char *iod_line);
|
||||
struct site get_site(int site_id);
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
double modulo(double x,double y);
|
||||
double gmst(double mjd);
|
||||
double dgmst(double mjd);
|
||||
double date2mjd(int year,int month,double day);
|
||||
void precess(double mjd0,double ra0,double de0,double mjd,double *ra,double *de);
|
||||
void usage();
|
||||
void obspos_xyz(double mjd,double lng,double lat,float alt,xyz_t *pos,xyz_t *vel);
|
||||
struct data read_data(char *filename);
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y);
|
||||
|
||||
void compute_residual(char *filename,struct point p)
|
||||
{
|
||||
int i,imode;
|
||||
FILE *file;
|
||||
orbit_t orb;
|
||||
xyz_t satpos,satvel;
|
||||
double dx,dy,dz;
|
||||
double r[2],ra,de;
|
||||
double rx[2],ry[2],dr,dt,drx,dry;
|
||||
double jd;
|
||||
double age;
|
||||
|
||||
// Open catalog
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL)
|
||||
fatal_error("Failed to open %s\n",filename);
|
||||
|
||||
// Read TLE
|
||||
read_twoline(file,p.satno,&orb);
|
||||
fclose(file);
|
||||
|
||||
// Check for match
|
||||
if (orb.satno!=p.satno) {
|
||||
// fprintf(stderr,"object %d not found in %s\n",p.satno,filename);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize
|
||||
imode=init_sgdp4(&orb);
|
||||
if (imode==SGDP4_ERROR) {
|
||||
fprintf(stderr,"Error initializing SGDP4\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for (i=0;i<2;i++) {
|
||||
jd=p.mjd+2400000.5+(double) i/86400;
|
||||
|
||||
// Compute position
|
||||
satpos_xyz(jd,&satpos,&satvel);
|
||||
age=jd-SGDP4_jd0;
|
||||
|
||||
// compute difference vector
|
||||
dx=satpos.x-p.obspos.x;
|
||||
dy=satpos.y-p.obspos.y;
|
||||
dz=satpos.z-p.obspos.z;
|
||||
|
||||
// Celestial position
|
||||
r[i]=sqrt(dx*dx+dy*dy+dz*dz);
|
||||
ra=modulo(atan2(dy,dx)*R2D,360.0);
|
||||
de=asin(dz/r[i])*R2D;
|
||||
|
||||
// Compute offset
|
||||
forward(p.ra,p.de,ra,de,&rx[i],&ry[i]);
|
||||
}
|
||||
drx=rx[1]-rx[0];
|
||||
dry=ry[1]-ry[0];
|
||||
dt=-(rx[0]*drx+ry[0]*dry)/(drx*drx+dry*dry);
|
||||
dr=sqrt(pow(dry*rx[0]-drx*ry[0],2)/(drx*drx+dry*dry));
|
||||
if ((-rx[0]*drx-ry[0]*dry)<0.0)
|
||||
dr*=-1;
|
||||
printf("%s | %8.3f deg %8.3f sec %5.1f day, %.1f km\n",p.iod_line,dr,dt,age,r[0]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i,arg=0;
|
||||
struct data d;
|
||||
char *datafile,catalog[LIM];
|
||||
char *env;
|
||||
|
||||
env=getenv("ST_TLEDIR");
|
||||
sprintf(catalog,"%s/classfd.tle",env);
|
||||
// Decode options
|
||||
while ((arg=getopt(argc,argv,"d:c:h"))!=-1) {
|
||||
switch(arg) {
|
||||
case 'd':
|
||||
datafile=optarg;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
strcpy(catalog,optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read data
|
||||
d=read_data(datafile);
|
||||
for (i=0;i<d.n;i++)
|
||||
compute_residual(catalog,d.p[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Decode IOD Observations
|
||||
struct point decode_iod_observation(char *iod_line)
|
||||
{
|
||||
int year,month,iday,hour,min;
|
||||
int format,epoch,me,xe,sign;
|
||||
int site_id;
|
||||
double sec,ra,mm,ss,de,dd,ds,day,mjd0;
|
||||
char secbuf[6],sn[2],degbuf[3];
|
||||
struct point p;
|
||||
struct site s;
|
||||
xyz_t vel;
|
||||
|
||||
// Strip newline
|
||||
iod_line[strlen(iod_line)-1]='\0';
|
||||
|
||||
// Copy full line
|
||||
strcpy(p.iod_line,iod_line);
|
||||
|
||||
// Set flag
|
||||
p.flag=1;
|
||||
|
||||
// Get SSN
|
||||
sscanf(iod_line,"%5d",&p.satno);
|
||||
|
||||
// Get site
|
||||
sscanf(iod_line+16,"%4d",&site_id);
|
||||
s=get_site(site_id);
|
||||
|
||||
// Decode date/time
|
||||
sscanf(iod_line+23,"%4d%2d%2d%2d%2d%5s",&year,&month,&iday,&hour,&min,secbuf);
|
||||
sec=atof(secbuf);
|
||||
sec/=pow(10,strlen(secbuf)-2);
|
||||
day=(double) iday+(double) hour/24.0+(double) min/1440.0+(double) sec/86400.0;
|
||||
p.mjd=date2mjd(year,month,day);
|
||||
|
||||
// Get uncertainty in time
|
||||
sscanf(iod_line+41,"%1d%1d",&me,&xe);
|
||||
p.st=(float) me*pow(10,xe-8);
|
||||
|
||||
// Get observer position
|
||||
obspos_xyz(p.mjd,s.lng,s.lat,s.alt,&p.obspos,&vel);
|
||||
|
||||
// Skip empty observations
|
||||
if (strlen(iod_line)<64 || (iod_line[54]!='+' && iod_line[54]!='-'))
|
||||
p.flag=0;
|
||||
|
||||
// Get format, epoch
|
||||
sscanf(iod_line+44,"%1d%1d",&format,&epoch);
|
||||
|
||||
// Read position
|
||||
sscanf(iod_line+47,"%2lf%2lf%3lf%1s",&ra,&mm,&ss,sn);
|
||||
sscanf(iod_line+55,"%2lf%2lf%2s",&de,&dd,degbuf);
|
||||
ds=atof(degbuf);
|
||||
if (strlen(degbuf)==1)
|
||||
ds*=10;
|
||||
sign=(sn[0]=='-') ? -1 : 1;
|
||||
sscanf(iod_line+62,"%1d%1d",&me,&xe);
|
||||
p.sr=(float) me*pow(10,xe-8);
|
||||
|
||||
// Decode position
|
||||
switch(format)
|
||||
{
|
||||
// Format 1: RA/DEC = HHMMSSs+DDMMSS MX (MX in seconds of arc)
|
||||
case 1 :
|
||||
ra+=mm/60+ss/36000;
|
||||
de=sign*(de+dd/60+ds/3600);
|
||||
p.sr/=3600.0;
|
||||
break;
|
||||
// Format 2: RA/DEC = HHMMmmm+DDMMmm MX (MX in minutes of arc)
|
||||
case 2:
|
||||
ra+=mm/60+ss/60000;
|
||||
de=sign*(de+dd/60+ds/6000);
|
||||
p.sr/=60.0;
|
||||
break;
|
||||
// Format 3: RA/DEC = HHMMmmm+DDdddd MX (MX in degrees of arc)
|
||||
case 3 :
|
||||
ra+=mm/60+ss/60000;
|
||||
de=sign*(de+dd/100+ds/10000);
|
||||
break;
|
||||
// Format 7: RA/DEC = HHMMSSs+DDdddd MX (MX in degrees of arc)
|
||||
case 7 :
|
||||
ra+=mm/60+ss/36000;
|
||||
de=sign*(de+dd/100+ds/10000);
|
||||
break;
|
||||
default :
|
||||
printf("IOD Format not implemented\n");
|
||||
p.flag=0;
|
||||
break;
|
||||
}
|
||||
// Convert to degrees
|
||||
ra*=15.0;
|
||||
|
||||
// Get precession epoch
|
||||
if (epoch==0) {
|
||||
p.ra=ra;
|
||||
p.de=de;
|
||||
return p;
|
||||
} else if (epoch==4) {
|
||||
mjd0=33281.9235;
|
||||
} else if (epoch==5) {
|
||||
mjd0=51544.5;
|
||||
} else {
|
||||
printf("Observing epoch not implemented\n");
|
||||
p.flag=0;
|
||||
}
|
||||
|
||||
// Precess position
|
||||
precess(mjd0,ra,de,p.mjd,&p.ra,&p.de);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
// Get observing site
|
||||
struct site get_site(int site_id)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
int id;
|
||||
double lat,lng;
|
||||
float alt;
|
||||
char abbrev[3],observer[64];
|
||||
struct site s;
|
||||
char *env,filename[LIM];
|
||||
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(filename,"%s/data/sites.txt",env);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
printf("File with site information not found!\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line,LIM,file)!=NULL) {
|
||||
// Skip
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
|
||||
// Strip newline
|
||||
line[strlen(line)-1]='\0';
|
||||
|
||||
// Read data
|
||||
sscanf(line,"%4d %2s %lf %lf %f",
|
||||
&id,abbrev,&lat,&lng,&alt);
|
||||
strcpy(observer,line+38);
|
||||
|
||||
// Change to km
|
||||
alt/=1000.0;
|
||||
|
||||
// Copy site
|
||||
if (id==site_id) {
|
||||
s.lat=lat;
|
||||
s.lng=lng;
|
||||
s.alt=alt;
|
||||
s.id=id;
|
||||
strcpy(s.observer,observer);
|
||||
}
|
||||
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return s;
|
||||
}
|
||||
// Return x modulo y [0,y)
|
||||
double modulo(double x,double y)
|
||||
{
|
||||
x=fmod(x,y);
|
||||
if (x<0.0) x+=y;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double gmst(double mjd)
|
||||
{
|
||||
double t,gmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
gmst=modulo(280.46061837+360.98564736629*(mjd-51544.5)+t*t*(0.000387933-t/38710000),360.0);
|
||||
|
||||
return gmst;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double dgmst(double mjd)
|
||||
{
|
||||
double t,dgmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
dgmst=360.98564736629+t*(0.000387933-t/38710000);
|
||||
|
||||
return dgmst;
|
||||
}
|
||||
|
||||
// Observer position
|
||||
void obspos_xyz(double mjd,double lng,double lat,float alt,xyz_t *pos,xyz_t *vel)
|
||||
{
|
||||
double ff,gc,gs,theta,s,dtheta;
|
||||
|
||||
s=sin(lat*D2R);
|
||||
ff=sqrt(1.0-FLAT*(2.0-FLAT)*s*s);
|
||||
gc=1.0/ff+alt/XKMPER;
|
||||
gs=(1.0-FLAT)*(1.0-FLAT)/ff+alt/XKMPER;
|
||||
|
||||
theta=gmst(mjd)+lng;
|
||||
dtheta=dgmst(mjd)*D2R/86400;
|
||||
|
||||
pos->x=gc*cos(lat*D2R)*cos(theta*D2R)*XKMPER;
|
||||
pos->y=gc*cos(lat*D2R)*sin(theta*D2R)*XKMPER;
|
||||
pos->z=gs*sin(lat*D2R)*XKMPER;
|
||||
vel->x=-gc*cos(lat*D2R)*sin(theta*D2R)*XKMPER*dtheta;
|
||||
vel->y=gc*cos(lat*D2R)*cos(theta*D2R)*XKMPER*dtheta;
|
||||
vel->z=0.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Precess a celestial position
|
||||
void precess(double mjd0,double ra0,double de0,double mjd,double *ra,double *de)
|
||||
{
|
||||
double t0,t;
|
||||
double zeta,z,theta;
|
||||
double a,b,c;
|
||||
|
||||
// Angles in radians
|
||||
ra0*=D2R;
|
||||
de0*=D2R;
|
||||
|
||||
// Time in centuries
|
||||
t0=(mjd0-51544.5)/36525.0;
|
||||
t=(mjd-mjd0)/36525.0;
|
||||
|
||||
// Precession angles
|
||||
zeta=(2306.2181+1.39656*t0-0.000139*t0*t0)*t;
|
||||
zeta+=(0.30188-0.000344*t0)*t*t+0.017998*t*t*t;
|
||||
zeta*=D2R/3600.0;
|
||||
z=(2306.2181+1.39656*t0-0.000139*t0*t0)*t;
|
||||
z+=(1.09468+0.000066*t0)*t*t+0.018203*t*t*t;
|
||||
z*=D2R/3600.0;
|
||||
theta=(2004.3109-0.85330*t0-0.000217*t0*t0)*t;
|
||||
theta+=-(0.42665+0.000217*t0)*t*t-0.041833*t*t*t;
|
||||
theta*=D2R/3600.0;
|
||||
|
||||
a=cos(de0)*sin(ra0+zeta);
|
||||
b=cos(theta)*cos(de0)*cos(ra0+zeta)-sin(theta)*sin(de0);
|
||||
c=sin(theta)*cos(de0)*cos(ra0+zeta)+cos(theta)*sin(de0);
|
||||
|
||||
*ra=(atan2(a,b)+z)*R2D;
|
||||
*de=asin(c)*R2D;
|
||||
|
||||
if (*ra<360.0)
|
||||
*ra+=360.0;
|
||||
if (*ra>360.0)
|
||||
*ra-=360.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\t')
|
||||
c=' ';
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
printf("bla\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute Julian Day from Date
|
||||
double date2mjd(int year,int month,double day)
|
||||
{
|
||||
int a,b;
|
||||
double jd;
|
||||
|
||||
if (month<3) {
|
||||
year--;
|
||||
month+=12;
|
||||
}
|
||||
|
||||
a=floor(year/100.);
|
||||
b=2.-a+floor(a/4.);
|
||||
|
||||
if (year<1582) b=0;
|
||||
if (year==1582 && month<10) b=0;
|
||||
if (year==1852 && month==10 && day<=4) b=0;
|
||||
|
||||
jd=floor(365.25*(year+4716))+floor(30.6001*(month+1))+day+b-1524.5;
|
||||
|
||||
return jd-2400000.5;
|
||||
}
|
||||
|
||||
// Read data
|
||||
struct data read_data(char *filename)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
struct data d;
|
||||
|
||||
// Open file
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
fprintf(stderr,"Failed to open %s\n",filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Count lines
|
||||
while (fgetline(file,line,LIM)>0)
|
||||
i++;
|
||||
d.n=i;
|
||||
|
||||
// Allocate
|
||||
d.p=(struct point *) malloc(sizeof(struct point)*d.n);
|
||||
|
||||
// Rewind file
|
||||
rewind(file);
|
||||
|
||||
// Read data
|
||||
i=0;
|
||||
while (fgetline(file,line,LIM)>0)
|
||||
d.p[i++]=decode_iod_observation(line);
|
||||
|
||||
// Close file
|
||||
fclose(file);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
// Get a x and y from an AZI, ALT
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y)
|
||||
{
|
||||
int i;
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset("STG",&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celfwd("STG",ra,de,&cel,&phi,&theta,&prj,x,y)) {
|
||||
printf("Error in Projection (celfwd)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#define PORT 7264
|
||||
#define IP "127.0.0.1"
|
||||
#define LIM 2048
|
||||
#define NMAX 128
|
||||
|
||||
#define SCHEDULED 0
|
||||
#define STARTED 1
|
||||
#define FINISHED 2
|
||||
|
||||
struct observation {
|
||||
char stime[20],sra[15],sde[15];
|
||||
time_t ptime;
|
||||
float dt;
|
||||
};
|
||||
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
void send_position(char *sra,char *sde);
|
||||
time_t decode_time(char *stm);
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i=0,nobs,flag=0;
|
||||
time_t rawtime,aimtime;
|
||||
struct tm *ptm,*rtm;
|
||||
char buf[20],line[LIM],stm[20],sra[15],sde[15],pra[15],pde[15];
|
||||
FILE *file;
|
||||
struct observation obs[NMAX];
|
||||
|
||||
// For ever loop
|
||||
for (;;) {
|
||||
// Read file
|
||||
i=0;
|
||||
file=fopen("schedule.txt","r");
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
sscanf(line,"%s %s %s",obs[i].stime,obs[i].sra,obs[i].sde);
|
||||
obs[i].ptime=decode_time(obs[i].stime);
|
||||
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
nobs=i;
|
||||
|
||||
// Get local time
|
||||
time(&rawtime);
|
||||
|
||||
// Print UTC time
|
||||
ptm=gmtime(&rawtime);
|
||||
strftime(buf,20,"%Y-%m-%dT%H:%M:%S",ptm);
|
||||
|
||||
// Compute time differences
|
||||
for (i=0;i<nobs;i++)
|
||||
obs[i].dt=difftime(obs[i].ptime,rawtime);
|
||||
|
||||
// Loop over observations
|
||||
for (i=0;i<nobs;i++) {
|
||||
if (obs[i].dt>0.0) {
|
||||
printf("%4.0f %s %s %s\n",obs[i].dt,obs[i].stime,obs[i].sra,obs[i].sde);
|
||||
break;
|
||||
} else if (obs[i].dt==0) {
|
||||
printf("Slewing to %s %s\n",obs[i].sra,obs[i].sde);
|
||||
send_position(obs[i].sra,obs[i].sde);
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
// Send new position to telescope
|
||||
void send_position(char *sra,char *sde)
|
||||
{
|
||||
int skt;
|
||||
struct hostent *he;
|
||||
struct sockaddr_in addr;
|
||||
char packet[LIM];
|
||||
FILE *file;
|
||||
|
||||
sprintf(packet,"<newNumberVector device='Celestron GPS' name='EQUATORIAL_EOD_COORD_REQUEST'><oneNumber name='RA'>%s</oneNumber><oneNumber name='DEC'>%s</oneNumber></newNumberVector>",sra,sde);
|
||||
|
||||
// Send TCP packet
|
||||
skt=socket(AF_INET,SOCK_STREAM,0);
|
||||
addr.sin_family=AF_INET;
|
||||
addr.sin_port=htons(PORT);
|
||||
he=gethostbyname(IP);
|
||||
bcopy(he->h_addr,(struct in_addr *) &addr.sin_addr,he->h_length);
|
||||
if(connect(skt,(struct sockaddr *) &addr,sizeof(addr))<0) {
|
||||
fprintf(stderr,"Connection refused by remote host.\n");
|
||||
return;
|
||||
}
|
||||
write(skt,packet,strlen(packet));
|
||||
close(skt);
|
||||
|
||||
// Set restart
|
||||
file=fopen("/media/video/satobs/control/state.txt","w");
|
||||
if (file!=NULL) {
|
||||
fprintf(file,"restart");
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
// Set position
|
||||
file=fopen("/media/video/satobs/control/position.txt","w");
|
||||
if (file!=NULL) {
|
||||
fprintf(file,"%s %s\n",sra,sde);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode time
|
||||
time_t decode_time(char *stm)
|
||||
{
|
||||
time_t aimtime;
|
||||
struct tm *rtm;
|
||||
int d;
|
||||
|
||||
rtm=gmtime(&aimtime);
|
||||
sscanf(stm,"%04d-%02d-%02dT%02d:%02d:%02d",&rtm->tm_year,&rtm->tm_mon,&rtm->tm_mday,&rtm->tm_hour,&rtm->tm_min,&rtm->tm_sec);
|
||||
rtm->tm_year-=1900;
|
||||
rtm->tm_mon--;
|
||||
aimtime=mktime(rtm);
|
||||
|
||||
return aimtime;
|
||||
}
|
|
@ -0,0 +1,666 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "cel.h"
|
||||
#include "cpgplot.h"
|
||||
#include "qfits.h"
|
||||
#include "sgdp4h.h"
|
||||
|
||||
#define LIM 80
|
||||
#define NMAX 256
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
#define XKMPER 6378.135 // Earth radius in km
|
||||
#define XKMPAU 149597879.691 // AU in km
|
||||
#define FLAT (1.0/298.257)
|
||||
#define STDMAG 6.0
|
||||
#define MMAX 10
|
||||
|
||||
long Isat=0;
|
||||
long Isatsel=0;
|
||||
extern double SGDP4_jd0;
|
||||
|
||||
struct map {
|
||||
double lat,lng;
|
||||
float alt;
|
||||
char observer[32];
|
||||
int site_id;
|
||||
} m;
|
||||
struct image {
|
||||
char filename[64];
|
||||
int naxis1,naxis2,nframes;
|
||||
float *zavg,*zstd,*zmax,*znum;
|
||||
double ra0,de0;
|
||||
float x0,y0;
|
||||
float a[3],b[3],xrms,yrms;
|
||||
double mjd;
|
||||
float *dt,exptime;
|
||||
char nfd[32];
|
||||
int cospar;
|
||||
};
|
||||
struct sat {
|
||||
long Isat;
|
||||
char state[10];
|
||||
float mag;
|
||||
double jd;
|
||||
double dx,dy,dz;
|
||||
double x,y,z,vx,vy,vz;
|
||||
double rsun,rearth;
|
||||
double psun,pearth,p,phase;
|
||||
double r,v,ra,de;
|
||||
double azi,alt;
|
||||
double rx,ry;
|
||||
};
|
||||
struct image read_fits(char *filename);
|
||||
struct sat apparent_position(double mjd);
|
||||
double modulo(double,double);
|
||||
void obspos_xyz(double,xyz_t *,xyz_t *);
|
||||
void sunpos_xyz(double,xyz_t *);
|
||||
double gmst(double);
|
||||
double dgmst(double);
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y);
|
||||
void reverse(double ra0,double de0,double x,double y,double *ra,double *de);
|
||||
|
||||
// Precess a celestial position
|
||||
void precess(double mjd0,double ra0,double de0,double mjd,double *ra,double *de)
|
||||
{
|
||||
double t0,t;
|
||||
double zeta,z,theta;
|
||||
double a,b,c;
|
||||
|
||||
// Angles in radians
|
||||
ra0*=D2R;
|
||||
de0*=D2R;
|
||||
|
||||
// Time in centuries
|
||||
t0=(mjd0-51544.5)/36525.0;
|
||||
t=(mjd-mjd0)/36525.0;
|
||||
|
||||
// Precession angles
|
||||
zeta=(2306.2181+1.39656*t0-0.000139*t0*t0)*t;
|
||||
zeta+=(0.30188-0.000344*t0)*t*t+0.017998*t*t*t;
|
||||
zeta*=D2R/3600.0;
|
||||
z=(2306.2181+1.39656*t0-0.000139*t0*t0)*t;
|
||||
z+=(1.09468+0.000066*t0)*t*t+0.018203*t*t*t;
|
||||
z*=D2R/3600.0;
|
||||
theta=(2004.3109-0.85330*t0-0.000217*t0*t0)*t;
|
||||
theta+=-(0.42665+0.000217*t0)*t*t-0.041833*t*t*t;
|
||||
theta*=D2R/3600.0;
|
||||
|
||||
a=cos(de0)*sin(ra0+zeta);
|
||||
b=cos(theta)*cos(de0)*cos(ra0+zeta)-sin(theta)*sin(de0);
|
||||
c=sin(theta)*cos(de0)*cos(ra0+zeta)+cos(theta)*sin(de0);
|
||||
|
||||
*ra=(atan2(a,b)+z)*R2D;
|
||||
*de=asin(c)*R2D;
|
||||
|
||||
if (*ra<360.0)
|
||||
*ra+=360.0;
|
||||
if (*ra>360.0)
|
||||
*ra-=360.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void plot_satellites(char *tlefile,struct image img,long satno,double mjd0,float dt,int color)
|
||||
{
|
||||
int i;
|
||||
orbit_t orb;
|
||||
struct sat s;
|
||||
int imode,flag,textflag;
|
||||
FILE *fp=NULL,*file;;
|
||||
xyz_t satpos,obspos,satvel,sunpos;
|
||||
double mjd,jd,dx,dy,dz;
|
||||
double rx,ry,ra,de,azi,alt,r,t,d;
|
||||
float x,y,x0,y0;
|
||||
char norad[7],satname[30];
|
||||
float isch;
|
||||
float rsun,rearth,psun,pearth,p;
|
||||
char filename[128];
|
||||
|
||||
cpgqch(&isch);
|
||||
|
||||
// Image determinant
|
||||
d=img.a[1]*img.b[2]-img.a[2]*img.b[1];
|
||||
|
||||
// Open TLE file
|
||||
fp=fopen(tlefile,"rb");
|
||||
if (fp==NULL)
|
||||
fatal_error("File open failed for reading %s\n",tlefile);
|
||||
|
||||
cpgsci(color);
|
||||
|
||||
// Open file
|
||||
sprintf(filename,"%s.id",img.filename);
|
||||
file=fopen(filename,"a");
|
||||
|
||||
// Read TLEs
|
||||
while (read_twoline(fp,satno,&orb)==0) {
|
||||
Isat=orb.satno;
|
||||
imode=init_sgdp4(&orb);
|
||||
|
||||
sprintf(norad," %05ld",Isat);
|
||||
|
||||
if (imode==SGDP4_ERROR)
|
||||
continue;
|
||||
|
||||
for (flag=0,textflag=0,i=0;i<MMAX;i++) {
|
||||
t=img.exptime*(float) i/(float) (MMAX-1);
|
||||
mjd=mjd0+t/86400.0;
|
||||
|
||||
// Compute apparent position
|
||||
s=apparent_position(mjd);
|
||||
|
||||
// Adjust for stationary camera
|
||||
s.ra+=gmst(img.mjd+0.5*img.exptime/86400.0)-gmst(mjd);
|
||||
|
||||
// Convert to rx,ry
|
||||
r=acos(sin(img.de0*D2R)*sin(s.de*D2R)+cos(img.de0*D2R)*cos(s.de*D2R)*cos((img.ra0-s.ra)*D2R))*R2D;
|
||||
if (r<90.0)
|
||||
forward(img.ra0,img.de0,s.ra,s.de,&s.rx,&s.ry);
|
||||
else
|
||||
continue;
|
||||
|
||||
// Convert image position
|
||||
dx=s.rx-img.a[0];
|
||||
dy=s.ry-img.b[0];
|
||||
x=(img.b[2]*dx-img.a[2]*dy)/d+img.x0;
|
||||
y=(img.a[1]*dy-img.b[1]*dx)/d+img.y0;
|
||||
|
||||
// Visibility
|
||||
if (s.p-s.pearth<-s.psun) {
|
||||
cpgsls(4);
|
||||
} else if (s.p-s.pearth>-s.psun && s.p-s.pearth<s.psun) {
|
||||
cpgsls(2);
|
||||
} else if (s.p-s.pearth>s.psun) {
|
||||
cpgsls(1);
|
||||
}
|
||||
|
||||
// Print name if in viewport
|
||||
if (x>0.0 && x<img.naxis1 && y>0.0 && y<img.naxis2 && textflag==0) {
|
||||
if (flag!=0)
|
||||
cpgdraw(x,y);
|
||||
cpgsch(0.65);
|
||||
cpgtext(x,y,norad);
|
||||
cpgsch(isch);
|
||||
cpgmove(x,y);
|
||||
textflag=1;
|
||||
}
|
||||
|
||||
if (i==0) {
|
||||
x0=x;
|
||||
y0=y;
|
||||
}
|
||||
|
||||
// Plot satellites
|
||||
if (flag==0) {
|
||||
cpgpt1(x,y,17);
|
||||
cpgmove(x,y);
|
||||
flag=1;
|
||||
} else {
|
||||
cpgdraw(x,y);
|
||||
}
|
||||
}
|
||||
if (textflag==1)
|
||||
fprintf(file,"%.23s %8.3f %8.3f %8.3f %8.3f %8.5f %s %s\n",img.nfd+1,x0,y0,x,y,img.exptime,norad,tlefile);
|
||||
|
||||
}
|
||||
fclose(fp);
|
||||
fclose(file);
|
||||
cpgsci(1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get observing site
|
||||
void get_site(int site_id)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
int id;
|
||||
double lat,lng;
|
||||
float alt;
|
||||
char abbrev[3],observer[64],filename[LIM],*env;
|
||||
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(filename,"%s/data/sites.txt",env);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
printf("File with site information not found!\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line,LIM,file)!=NULL) {
|
||||
// Skip
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
|
||||
// Strip newline
|
||||
line[strlen(line)-1]='\0';
|
||||
|
||||
// Read data
|
||||
sscanf(line,"%4d %2s %lf %lf %f",
|
||||
&id,abbrev,&lat,&lng,&alt);
|
||||
strcpy(observer,line+38);
|
||||
|
||||
// Change to km
|
||||
alt/=1000.0;
|
||||
|
||||
if (id==site_id) {
|
||||
m.lat=lat;
|
||||
m.lng=lng;
|
||||
m.alt=alt;
|
||||
m.site_id=id;
|
||||
strcpy(m.observer,observer);
|
||||
}
|
||||
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
struct image img;
|
||||
float zmin,zmax,zavg,zstd;
|
||||
float tr[]={-0.5,1.0,0.0,-0.5,0.0,1.0};
|
||||
float heat_l[] = {0.0, 0.2, 0.4, 0.6, 1.0};
|
||||
float heat_r[] = {0.0, 0.5, 1.0, 1.0, 1.0};
|
||||
float heat_g[] = {0.0, 0.0, 0.5, 1.0, 1.0};
|
||||
float heat_b[] = {0.0, 0.0, 0.0, 0.3, 1.0};
|
||||
char text[128];
|
||||
char *env,filename[128];
|
||||
|
||||
img=read_fits(argv[1]);
|
||||
|
||||
// Set site
|
||||
env=getenv("ST_COSPAR");
|
||||
get_site(atoi(env));
|
||||
|
||||
|
||||
for (i=0,zavg=0.0;i<img.naxis1*img.naxis2;i++)
|
||||
zavg+=img.zmax[i];
|
||||
zavg/=(float) img.naxis1*img.naxis2;
|
||||
for (i=0,zstd=0.0;i<img.naxis1*img.naxis2;i++)
|
||||
zstd+=pow(img.zmax[i]-zavg,2);
|
||||
zstd=sqrt(zstd/(float) (img.naxis1*img.naxis2));
|
||||
zmin=zavg-2*zstd;
|
||||
zmax=zavg+6*zstd;
|
||||
|
||||
if (argc==3)
|
||||
cpgopen(argv[2]);
|
||||
else
|
||||
cpgopen("/xs");
|
||||
cpgpap(0.,1.0);
|
||||
cpgsvp(0.1,0.95,0.1,0.8);
|
||||
|
||||
cpgsch(0.8);
|
||||
sprintf(text,"UT Date: %.23s COSPAR ID: %04d",img.nfd+1,img.cospar);
|
||||
cpgmtxt("T",6.0,0.0,0.0,text);
|
||||
sprintf(text,"R.A.: %10.5f (%4.1f'') Decl.: %10.5f (%4.1f'')",img.ra0,img.xrms,img.de0,img.yrms);
|
||||
cpgmtxt("T",4.8,0.0,0.0,text);
|
||||
sprintf(text,"FoV: %.2f\\(2218)x%.2f\\(2218) Scale: %.2f''x%.2f'' pix\\u-1\\d",img.naxis1*sqrt(img.a[1]*img.a[1]+img.b[1]*img.b[1])/3600.0,img.naxis2*sqrt(img.a[2]*img.a[2]+img.b[2]*img.b[2])/3600.0,sqrt(img.a[1]*img.a[1]+img.b[1]*img.b[1]),sqrt(img.a[2]*img.a[2]+img.b[2]*img.b[2]));
|
||||
cpgmtxt("T",3.6,0.0,0.0,text);
|
||||
sprintf(text,"Stat: %5.1f+-%.1f (%.1f-%.1f)",zavg,zstd,zmin,zmax);
|
||||
cpgmtxt("T",2.4,0.0,0.0,text);
|
||||
|
||||
cpgsch(1.0);
|
||||
cpgwnad(0.0,img.naxis1,0.0,img.naxis2);
|
||||
|
||||
cpglab("x (pix)","y (pix)"," ");
|
||||
cpgctab (heat_l,heat_r,heat_g,heat_b,5,1.0,0.5);
|
||||
|
||||
cpgimag(img.zmax,img.naxis1,img.naxis2,1,img.naxis1,1,img.naxis2,zmin,zmax,tr);
|
||||
cpgbox("BCTSNI",0.,0,"BCTSNI",0.,0);
|
||||
|
||||
cpgstbg(1);
|
||||
|
||||
// Environment variables
|
||||
env=getenv("ST_TLEDIR");
|
||||
sprintf(filename,"%s/classfd.tle",env);
|
||||
plot_satellites(filename,img,0,img.mjd,img.exptime,4);
|
||||
sprintf(filename,"%s/catalog.tle",env);
|
||||
plot_satellites(filename,img,0,img.mjd,img.exptime,0);
|
||||
|
||||
cpgend();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read fits image
|
||||
struct image read_fits(char *filename)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
struct image img;
|
||||
|
||||
// Copy filename
|
||||
strcpy(img.filename,filename);
|
||||
|
||||
// Image size
|
||||
img.naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
img.naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
|
||||
// MJD
|
||||
img.mjd=(double) atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
strcpy(img.nfd,qfits_query_hdr(filename,"DATE-OBS"));
|
||||
img.exptime=atof(qfits_query_hdr(filename,"EXPTIME"));
|
||||
|
||||
// COSPAR ID
|
||||
img.cospar=atoi(qfits_query_hdr(filename,"COSPAR"));
|
||||
|
||||
// Transformation
|
||||
img.mjd=atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
img.ra0=atof(qfits_query_hdr(filename,"CRVAL1"));
|
||||
img.de0=atof(qfits_query_hdr(filename,"CRVAL2"));
|
||||
img.x0=atof(qfits_query_hdr(filename,"CRPIX1"));
|
||||
img.y0=atof(qfits_query_hdr(filename,"CRPIX2"));
|
||||
img.a[0]=0.0;
|
||||
img.a[1]=3600.0*atof(qfits_query_hdr(filename,"CD1_1"));
|
||||
img.a[2]=3600.0*atof(qfits_query_hdr(filename,"CD1_2"));
|
||||
img.b[0]=0.0;
|
||||
img.b[1]=3600.0*atof(qfits_query_hdr(filename,"CD2_1"));
|
||||
img.b[2]=3600.0*atof(qfits_query_hdr(filename,"CD2_2"));
|
||||
img.xrms=3600.0*atof(qfits_query_hdr(filename,"CRRES1"));
|
||||
img.yrms=3600.0*atof(qfits_query_hdr(filename,"CRRES2"));
|
||||
img.nframes=atoi(qfits_query_hdr(filename,"NFRAMES"));
|
||||
|
||||
// Timestamps
|
||||
img.dt=(float *) malloc(sizeof(float)*img.nframes);
|
||||
for (i=0;i<img.nframes;i++) {
|
||||
sprintf(key,"DT%04d",i);
|
||||
strcpy(val,qfits_query_hdr(filename,key));
|
||||
sscanf(val+1,"%f",&img.dt[i]);
|
||||
// img.dt[i]=atof(qfits_query_hdr(filename,key));
|
||||
}
|
||||
|
||||
// Allocate image memory
|
||||
img.zavg=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.zstd=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.zmax=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.znum=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
|
||||
// Set parameters
|
||||
ql.xtnum=0;
|
||||
ql.ptype=PTYPE_FLOAT;
|
||||
ql.filename=filename;
|
||||
|
||||
// Loop over planes
|
||||
for (k=0;k<4;k++) {
|
||||
ql.pnum=k;;
|
||||
|
||||
// Initialize load
|
||||
if (qfitsloader_init(&ql) != 0)
|
||||
printf("Error initializing data loading\n");
|
||||
|
||||
// Test load
|
||||
if (qfits_loadpix(&ql) != 0)
|
||||
printf("Error loading actual data\n");
|
||||
|
||||
// Fill z array
|
||||
for (i=0,l=0;i<img.naxis1;i++) {
|
||||
for (j=0;j<img.naxis2;j++) {
|
||||
if (k==0) img.zavg[l]=ql.fbuf[l];
|
||||
if (k==1) img.zstd[l]=ql.fbuf[l];
|
||||
if (k==2) img.zmax[l]=ql.fbuf[l];
|
||||
if (k==3) img.znum[l]=ql.fbuf[l];
|
||||
l++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
// Computes apparent position
|
||||
struct sat apparent_position(double mjd)
|
||||
{
|
||||
struct sat s;
|
||||
double jd,rsun,rearth,rsat;
|
||||
double dx,dy,dz,dvx,dvy,dvz;
|
||||
xyz_t satpos,obspos,obsvel,satvel,sunpos;
|
||||
double ra,de;
|
||||
double mjd0=51544.5;
|
||||
|
||||
// Sat ID
|
||||
s.Isat=Isat;
|
||||
|
||||
// Get Julian Date
|
||||
jd=mjd+2400000.5;
|
||||
|
||||
// Get positions
|
||||
obspos_xyz(mjd,&obspos,&obsvel);
|
||||
satpos_xyz(jd,&satpos,&satvel);
|
||||
sunpos_xyz(mjd,&sunpos);
|
||||
|
||||
// Sat positions
|
||||
s.x=satpos.x;
|
||||
s.y=satpos.y;
|
||||
s.z=satpos.z;
|
||||
s.vx=satvel.x;
|
||||
s.vy=satvel.y;
|
||||
s.vz=satvel.z;
|
||||
|
||||
// Sun position from satellite
|
||||
dx=-satpos.x+sunpos.x;
|
||||
dy=-satpos.y+sunpos.y;
|
||||
dz=-satpos.z+sunpos.z;
|
||||
|
||||
// Distances
|
||||
rsun=sqrt(dx*dx+dy*dy+dz*dz);
|
||||
rearth=sqrt(satpos.x*satpos.x+satpos.y*satpos.y+satpos.z*satpos.z);
|
||||
|
||||
// Angles
|
||||
s.psun=asin(696.0e3/rsun)*R2D;
|
||||
s.pearth=asin(6378.135/rearth)*R2D;
|
||||
s.p=acos((-dx*satpos.x-dy*satpos.y-dz*satpos.z)/(rsun*rearth))*R2D;
|
||||
|
||||
// Visibility state
|
||||
if (s.p-s.pearth<-s.psun)
|
||||
strcpy(s.state,"eclipsed");
|
||||
else if (s.p-s.pearth>-s.psun && s.p-s.pearth<s.psun)
|
||||
strcpy(s.state,"umbra");
|
||||
else if (s.p-s.pearth>s.psun)
|
||||
strcpy(s.state,"sunlit");
|
||||
|
||||
// Position differences
|
||||
dx=satpos.x-obspos.x;
|
||||
dy=satpos.y-obspos.y;
|
||||
dz=satpos.z-obspos.z;
|
||||
dvx=satvel.x-obsvel.x;
|
||||
dvy=satvel.y-obsvel.y;
|
||||
dvz=satvel.z-obsvel.z;
|
||||
|
||||
// Celestial position
|
||||
s.r=sqrt(dx*dx+dy*dy+dz*dz);
|
||||
s.v=(dvx*dx+dvy*dy+dvz*dz)/s.r;
|
||||
ra=modulo(atan2(dy,dx)*R2D,360.0);
|
||||
de=asin(dz/s.r)*R2D;
|
||||
|
||||
// Precess
|
||||
precess(mjd,ra,de,mjd0,&s.ra,&s.de);
|
||||
|
||||
// Phase
|
||||
s.phase=acos(((obspos.x-satpos.x)*(sunpos.x-satpos.x)+(obspos.y-satpos.y)*(sunpos.y-satpos.y)+(obspos.z-satpos.z)*(sunpos.z-satpos.z))/(rsun*s.r))*R2D;
|
||||
|
||||
// Magnitude
|
||||
if (strcmp(s.state,"sunlit")==0)
|
||||
s.mag=STDMAG-15.0+5*log10(s.r)-2.5*log10(sin(s.phase*D2R)+(M_PI-s.phase*D2R)*cos(s.phase*D2R));
|
||||
else
|
||||
s.mag=15;
|
||||
|
||||
/*
|
||||
// Convert and project
|
||||
if (strcmp(m.orientation,"horizontal")==0) {
|
||||
equatorial2horizontal(mjd,s.ra,s.de,&s.azi,&s.alt);
|
||||
forward(s.azi,s.alt,&s.rx,&s.ry);
|
||||
} else if (strcmp(m.orientation,"equatorial")==0) {
|
||||
forward(s.ra,s.de,&s.rx,&s.ry);
|
||||
}
|
||||
*/
|
||||
return s;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double gmst(double mjd)
|
||||
{
|
||||
double t,gmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
gmst=modulo(280.46061837+360.98564736629*(mjd-51544.5)+t*t*(0.000387933-t/38710000),360.0);
|
||||
|
||||
return gmst;
|
||||
}
|
||||
|
||||
// Return x modulo y [0,y)
|
||||
double modulo(double x,double y)
|
||||
{
|
||||
x=fmod(x,y);
|
||||
if (x<0.0) x+=y;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// Observer position
|
||||
void obspos_xyz(double mjd,xyz_t *pos,xyz_t *vel)
|
||||
{
|
||||
double ff,gc,gs,theta,s,dtheta;
|
||||
|
||||
s=sin(m.lat*D2R);
|
||||
ff=sqrt(1.0-FLAT*(2.0-FLAT)*s*s);
|
||||
gc=1.0/ff+m.alt/XKMPER;
|
||||
gs=(1.0-FLAT)*(1.0-FLAT)/ff+m.alt/XKMPER;
|
||||
|
||||
theta=gmst(mjd)+m.lng;
|
||||
dtheta=dgmst(mjd)*D2R/86400;
|
||||
|
||||
pos->x=gc*cos(m.lat*D2R)*cos(theta*D2R)*XKMPER;
|
||||
pos->y=gc*cos(m.lat*D2R)*sin(theta*D2R)*XKMPER;
|
||||
pos->z=gs*sin(m.lat*D2R)*XKMPER;
|
||||
vel->x=-gc*cos(m.lat*D2R)*sin(theta*D2R)*XKMPER*dtheta;
|
||||
vel->y=gc*cos(m.lat*D2R)*cos(theta*D2R)*XKMPER*dtheta;
|
||||
vel->z=0.0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Solar position
|
||||
void sunpos_xyz(double mjd,xyz_t *pos)
|
||||
{
|
||||
double jd,t,l0,m,e,c,r;
|
||||
double n,s,ecl,ra,de;
|
||||
|
||||
jd=mjd+2400000.5;
|
||||
t=(jd-2451545.0)/36525.0;
|
||||
l0=modulo(280.46646+t*(36000.76983+t*0.0003032),360.0)*D2R;
|
||||
m=modulo(357.52911+t*(35999.05029-t*0.0001537),360.0)*D2R;
|
||||
e=0.016708634+t*(-0.000042037-t*0.0000001267);
|
||||
c=(1.914602+t*(-0.004817-t*0.000014))*sin(m)*D2R;
|
||||
c+=(0.019993-0.000101*t)*sin(2.0*m)*D2R;
|
||||
c+=0.000289*sin(3.0*m)*D2R;
|
||||
|
||||
r=1.000001018*(1.0-e*e)/(1.0+e*cos(m+c));
|
||||
n=modulo(125.04-1934.136*t,360.0)*D2R;
|
||||
s=l0+c+(-0.00569-0.00478*sin(n))*D2R;
|
||||
ecl=(23.43929111+(-46.8150*t-0.00059*t*t+0.001813*t*t*t)/3600.0+0.00256*cos(n))*D2R;
|
||||
|
||||
ra=atan2(cos(ecl)*sin(s),cos(s));
|
||||
de=asin(sin(ecl)*sin(s));
|
||||
|
||||
pos->x=r*cos(de)*cos(ra)*XKMPAU;
|
||||
pos->y=r*cos(de)*sin(ra)*XKMPAU;
|
||||
pos->z=r*sin(de)*XKMPAU;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double dgmst(double mjd)
|
||||
{
|
||||
double t,dgmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
dgmst=360.98564736629+t*(0.000387933-t/38710000);
|
||||
|
||||
return dgmst;
|
||||
}
|
||||
|
||||
// Get a x and y from a RA and Decl
|
||||
void forward(double ra0,double de0,double ra,double de,double *x,double *y)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="TAN";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celfwd(pcode,ra,de,&cel,&phi,&theta,&prj,x,y)) {
|
||||
printf("Error in Projection (celfwd)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
*x*=3600.;
|
||||
*y*=3600.;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a RA and Decl from x and y
|
||||
void reverse(double ra0,double de0,double x,double y,double *ra,double *de)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="TAN";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
|
||||
x/=3600.;
|
||||
y/=3600.;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celrev(pcode,x,y,&prj,&phi,&theta,&cel,ra,de)) {
|
||||
printf("Error in Projection (celrev)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,869 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <getopt.h>
|
||||
#include "cpgplot.h"
|
||||
#include "sgdp4h.h"
|
||||
|
||||
#define LIM 80
|
||||
#define NMAX 1024
|
||||
#define MMAX 28368
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
#define XKMPER 6378.135 // Earth radius in km
|
||||
#define FLAT (1.0/298.257)
|
||||
#define XKMPAU 149597879.691 // AU in km
|
||||
|
||||
long Isat=0;
|
||||
long Isatsel=0;
|
||||
extern double SGDP4_jd0;
|
||||
|
||||
struct map {
|
||||
long satno;
|
||||
double lat,lng;
|
||||
double mjd;
|
||||
float alt,timezone;
|
||||
int length;
|
||||
char nfd[LIM],tlefile[LIM],observer[32];
|
||||
char datadir[LIM],tledir[LIM];
|
||||
int site_id;
|
||||
float l0,b0;
|
||||
} m;
|
||||
struct globe {
|
||||
int n;
|
||||
float l[MMAX],b[MMAX];
|
||||
} glb;
|
||||
struct sat {
|
||||
long Isat;
|
||||
double jd;
|
||||
double dx,dy,dz;
|
||||
double x,y,z,vx,vy,vz;
|
||||
double rsun,rearth;
|
||||
double psun,pearth,p;
|
||||
double r,ra,de;
|
||||
double azi,alt;
|
||||
double rx,ry;
|
||||
};
|
||||
void read_globe(void);
|
||||
void plot_globe(void);
|
||||
void initialize_setup(void);
|
||||
double nfd2mjd(char *date);
|
||||
double date2mjd(int year,int month,double day);
|
||||
void mjd2date(double mjd,char *date,int length);
|
||||
void usage();
|
||||
void nfd_now(char *s);
|
||||
double gmst(double);
|
||||
double dgmst(double);
|
||||
double modulo(double,double);
|
||||
void sunpos_xyz(double,xyz_t *,double *,double *);
|
||||
void rotate(int axis,float angle,float *x,float *y,float *z);
|
||||
void get_site(int site_id);
|
||||
|
||||
void plot_terminator(void)
|
||||
{
|
||||
int i,j,j0,k,flag;
|
||||
xyz_t sunpos;
|
||||
double sra,sde,r,h;
|
||||
float l0,b0,l[NMAX+4],b[NMAX+4];
|
||||
float x,y,z;
|
||||
int isci;
|
||||
float theta,ang[]={0.0,-6.0,-12.0,-18.0};
|
||||
|
||||
// Solar position
|
||||
sunpos_xyz(m.mjd,&sunpos,&sra,&sde);
|
||||
|
||||
// GMST
|
||||
h=gmst(m.mjd);
|
||||
|
||||
// Solar subpoint
|
||||
l0=modulo(sra-h,360.0);
|
||||
b0=sde;
|
||||
if (l0>180.0)
|
||||
l0-=360.0;
|
||||
|
||||
// Loop over terminator boundaries
|
||||
for (k=0;k<4;k++) {
|
||||
for (i=0,j=0,flag=0;i<NMAX;i++,j++) {
|
||||
theta=2.0*M_PI*(float) i/(float) (NMAX-1);
|
||||
|
||||
x=XKMPER*sin(ang[k]*D2R);
|
||||
y=XKMPER*sin(theta)*cos(ang[k]*D2R);
|
||||
z=XKMPER*cos(theta)*cos(ang[k]*D2R);
|
||||
|
||||
rotate(1,b0,&x,&y,&z);
|
||||
rotate(2,l0,&x,&y,&z);
|
||||
|
||||
r=sqrt(x*x+y*y+z*z);
|
||||
l[j]=atan2(y,x)*R2D;
|
||||
b[j]=asin(z/r)*R2D;
|
||||
l[j]=modulo(l[j],360.0);
|
||||
if (l[j]>180.0)
|
||||
l[j]-=360.0;
|
||||
if (l[j]<-180.0)
|
||||
l[j]+=360.0;
|
||||
|
||||
// Passing limit left to right
|
||||
if (l[j]*l[j-1]<0.0 && fabs(l[j])>45.0 && flag==0 && k==0) {
|
||||
l[j+4]=l[j];
|
||||
b[j+4]=b[j];
|
||||
b[j]=b[j-1];
|
||||
b[j+3]=b[j-1];
|
||||
if (l[j-1]<l[j]) {
|
||||
l[j]=-180.0;
|
||||
l[j+1]=-180.0;
|
||||
l[j+2]=180.0;
|
||||
l[j+3]=180.0;
|
||||
} else {
|
||||
l[j]=180.0;
|
||||
l[j+1]=180.0;
|
||||
l[j+2]=-180.0;
|
||||
l[j+3]=-180.0;
|
||||
}
|
||||
if (b0<=0.0) {
|
||||
b[j+1]=90.0;
|
||||
b[j+2]=90.0;
|
||||
} else {
|
||||
b[j+1]=-90.0;
|
||||
b[j+2]=-90.0;
|
||||
}
|
||||
j+=4;
|
||||
flag=1;
|
||||
}
|
||||
}
|
||||
|
||||
if (k==0) {
|
||||
// Set night color
|
||||
cpgscr(16,0.0,0.0,0.2);
|
||||
|
||||
// Plot night side
|
||||
cpgsci(16);
|
||||
cpgpoly(NMAX+4,l,b);
|
||||
|
||||
// Plot terminator
|
||||
cpgsci(14);
|
||||
cpgline(NMAX+4,l,b);
|
||||
cpgsci(1);
|
||||
} else {
|
||||
// Plot twilight boundaries
|
||||
cpgsci(14);
|
||||
for (i=0,flag=0;i<NMAX;i++) {
|
||||
if (i>0 && l[i-1]*l[i]<0.0 && fabs(l[i-1]-l[i])>10.0)
|
||||
flag=0;
|
||||
|
||||
if (flag==0) {
|
||||
cpgmove(l[i],b[i]);
|
||||
flag=1;
|
||||
} else {
|
||||
cpgdraw(l[i],b[i]);
|
||||
}
|
||||
}
|
||||
cpgsci(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Save sub solar position
|
||||
m.l0=l0;
|
||||
m.b0=b0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void init_plot(char *psfile,float width,float aspect)
|
||||
{
|
||||
|
||||
cpgopen(psfile);
|
||||
cpgslw(2);
|
||||
cpgpap(width,aspect);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Plot observing sites
|
||||
void plot_sites(void)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
int id;
|
||||
double lat,lng;
|
||||
float alt;
|
||||
char abbrev[3],observer[64],text[8],filename[LIM];
|
||||
float isch;
|
||||
|
||||
cpgqch(&isch);
|
||||
|
||||
sprintf(filename,"%s/data/sites.txt",m.datadir);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
printf("File with site information not found!\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line,LIM,file)!=NULL) {
|
||||
// Skip
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
|
||||
// Strip newline
|
||||
line[strlen(line)-1]='\0';
|
||||
|
||||
// Read data
|
||||
sscanf(line,"%4d %2s %lf %lf %f",
|
||||
&id,abbrev,&lat,&lng,&alt);
|
||||
strcpy(observer,line+38);
|
||||
|
||||
sprintf(text," %04d",id);
|
||||
cpgsci(2);
|
||||
cpgsch(0.5);
|
||||
cpgpt1(lng,lat,4);
|
||||
cpgtext(lng,lat,text);
|
||||
cpgsci(1);
|
||||
}
|
||||
fclose(file);
|
||||
cpgsch(isch);
|
||||
|
||||
return;
|
||||
}
|
||||
// Computes apparent position
|
||||
struct sat apparent_position(double mjd)
|
||||
{
|
||||
struct sat s;
|
||||
double jd,rsun,rearth;
|
||||
double dx,dy,dz;
|
||||
xyz_t satpos,obspos,satvel,sunpos;
|
||||
double sra,sde;
|
||||
|
||||
// Sat ID
|
||||
s.Isat=Isat;
|
||||
|
||||
// Get Julian Date
|
||||
jd=mjd+2400000.5;
|
||||
|
||||
// Get positions
|
||||
satpos_xyz(jd,&satpos,&satvel);
|
||||
sunpos_xyz(mjd,&sunpos,&sra,&sde);
|
||||
|
||||
// Sat positions
|
||||
s.x=satpos.x;
|
||||
s.y=satpos.y;
|
||||
s.z=satpos.z;
|
||||
s.vx=satvel.x;
|
||||
s.vy=satvel.y;
|
||||
s.vz=satvel.y;
|
||||
|
||||
// Sun position from satellite
|
||||
dx=-satpos.x+sunpos.x;
|
||||
dy=-satpos.y+sunpos.y;
|
||||
dz=-satpos.z+sunpos.z;
|
||||
|
||||
// Distances
|
||||
rsun=sqrt(dx*dx+dy*dy+dz*dz);
|
||||
rearth=sqrt(satpos.x*satpos.x+satpos.y*satpos.y+satpos.z*satpos.z);
|
||||
// Angles
|
||||
s.psun=asin(696.0e3/rsun)*R2D;
|
||||
s.pearth=asin(6378.135/rearth)*R2D;
|
||||
s.p=acos((-dx*satpos.x-dy*satpos.y-dz*satpos.z)/(rsun*rearth))*R2D;
|
||||
// s.p=acos(((sunpos.x+satpos.x)*satpos.x+(sunpos.y+satpos.y)*satpos.y+(sunpos.z+satpos.z)*satpos.z)/(rsun*rearth))*R2D;
|
||||
|
||||
s.p-=s.pearth;
|
||||
|
||||
// Celestial position
|
||||
s.r=sqrt(satpos.x*satpos.x+satpos.y*satpos.y+satpos.z*satpos.z);
|
||||
s.ra=atan2(satpos.y,satpos.x)*R2D;
|
||||
s.de=asin(satpos.z/s.r)*R2D;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// plot satellite track
|
||||
void track_plot_track(char *tlefile,long satno,double mjd0)
|
||||
{
|
||||
int i=0,nstep=500;
|
||||
orbit_t orb;
|
||||
xyz_t pos,vel;
|
||||
double jd,dt,h,l,b,l0,mjd;
|
||||
FILE *fp=NULL;
|
||||
float x,y,z,r,v;
|
||||
long imode;
|
||||
int isci;
|
||||
float isch;
|
||||
char norad[7];
|
||||
struct sat s;
|
||||
|
||||
cpgqci(&isci);
|
||||
cpgqch(&isch);
|
||||
cpgsci(7);
|
||||
|
||||
fp = fopen(tlefile, "rb");
|
||||
if(fp == NULL) {
|
||||
fatal_error("File open failed for reading \"%s\"", tlefile);
|
||||
}
|
||||
|
||||
while(read_twoline(fp, satno, &orb) == 0) {
|
||||
// print_orb(&orb);
|
||||
|
||||
Isat = orb.satno;
|
||||
imode = init_sgdp4(&orb);
|
||||
|
||||
if(imode == SGDP4_ERROR) continue;
|
||||
|
||||
jd=mjd0+2400000.5;
|
||||
for (i=0;;i++) {
|
||||
// if(satpos_xyz(jd, &pos, &vel) == SGDP4_ERROR) break;
|
||||
mjd=jd-2400000.5;
|
||||
s=apparent_position(mjd);
|
||||
|
||||
h=gmst(mjd);
|
||||
|
||||
x=s.x;
|
||||
y=s.y;
|
||||
z=s.z;
|
||||
|
||||
// Celestial position
|
||||
r=sqrt(x*x+y*y+z*z);
|
||||
l=atan2(y,x)*R2D;
|
||||
b=asin(z/r)*R2D;
|
||||
l-=h;
|
||||
l=modulo(l,360.0);
|
||||
if (l>180.0)
|
||||
l-=360.0;
|
||||
if (l<-180.0)
|
||||
l+=360.0;
|
||||
|
||||
// Visibility
|
||||
if (s.p<-s.psun)
|
||||
cpgsci(14);
|
||||
else if (s.p>-s.psun && s.p<s.psun)
|
||||
cpgsci(15);
|
||||
else if (s.p>s.psun)
|
||||
cpgsci(7);
|
||||
|
||||
// Plot
|
||||
if (i==0) {
|
||||
sprintf(norad," %5ld",Isat);
|
||||
cpgsch(0.6);
|
||||
cpgtext(l,b,norad);
|
||||
cpgsch(isch);
|
||||
cpgpt1(l,b,17);
|
||||
l0=l;
|
||||
}
|
||||
if (i==0 || fabs(l-l0)>10.0)
|
||||
cpgmove(l,b);
|
||||
else
|
||||
cpgdraw(l,b);
|
||||
l0=l;
|
||||
|
||||
// Do timestep
|
||||
r=sqrt(s.x*s.x+s.y*s.y+s.z*s.z);
|
||||
v=sqrt(s.vx*s.vx+s.vy*s.vy+s.vz*s.vz);
|
||||
dt=2.0*M_PI*r/(0.75*v*nstep);
|
||||
jd+=dt/86400.0;
|
||||
|
||||
if (i==nstep)
|
||||
break;
|
||||
}
|
||||
}
|
||||
cpgsci(isci);
|
||||
cpgsch(isch);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void plot_map(void)
|
||||
{
|
||||
int redraw=1;
|
||||
char text[256];
|
||||
float x,y;
|
||||
char c;
|
||||
|
||||
for (;;) {
|
||||
if (redraw>0) {
|
||||
// Get present mjd
|
||||
if (m.mjd<0.0) {
|
||||
nfd_now(m.nfd);
|
||||
m.mjd=nfd2mjd(m.nfd);
|
||||
}
|
||||
|
||||
cpgscr(0,0.0,0.0,0.0);
|
||||
cpgeras();
|
||||
|
||||
// Create window
|
||||
cpgsvp(0.01,0.99,0.01,0.99);
|
||||
cpgwnad(-180.0,180.0,-90.0,90.0);
|
||||
|
||||
// Set background
|
||||
cpgscr(0,0.0,0.0,0.5);
|
||||
cpgsci(0);
|
||||
cpgrect(-180.0,180.0,-90.0,90.0);
|
||||
cpgsci(1);
|
||||
cpgscr(0,0.0,0.0,0.0);
|
||||
cpgbox("BC",0.,0,"BC",0.,0);
|
||||
|
||||
// Top left string
|
||||
cpgsch(0.8);
|
||||
mjd2date(m.mjd,m.nfd,0);
|
||||
sprintf(text,"%s UTC",m.nfd);
|
||||
cpgmtxt("T",0.6,0.0,0.0,text);
|
||||
|
||||
// Bottom string
|
||||
sprintf(text,"l: %d s",m.length);
|
||||
cpgmtxt("B",1.0,0.0,0.0,text);
|
||||
cpgsch(1.0);
|
||||
|
||||
// Plot terminator
|
||||
plot_terminator();
|
||||
cpgsci(14);
|
||||
cpgbox("ABCG",30.,3,"ABCG",30.,3);
|
||||
cpgsci(1);
|
||||
|
||||
// Plot globe
|
||||
plot_globe();
|
||||
cpgsci(1);
|
||||
cpgbox("BCTS",30.,3,"BCTS",30.,3);
|
||||
|
||||
// Plot sites
|
||||
plot_sites();
|
||||
|
||||
// Plot satellites
|
||||
track_plot_track(m.tlefile,m.satno,m.mjd);
|
||||
|
||||
// Plot sub solar position
|
||||
cpgsci(7);
|
||||
cpgpt1(m.l0,m.b0,17);
|
||||
cpgsci(1);
|
||||
}
|
||||
|
||||
// Reset redraw
|
||||
redraw=0;
|
||||
|
||||
// Get cursor
|
||||
cpgcurs(&x,&y,&c);
|
||||
|
||||
// Redraw
|
||||
if (c=='r') {
|
||||
m.mjd=-1.0;
|
||||
m.length=60;
|
||||
redraw=1;
|
||||
}
|
||||
// Increase/decrease time
|
||||
if (c=='.') {
|
||||
m.mjd+=m.length/86400.0;
|
||||
redraw=1;
|
||||
}
|
||||
if (c==',') {
|
||||
m.mjd-=m.length/86400.0;
|
||||
redraw=1;
|
||||
}
|
||||
|
||||
// Increase/decrease step
|
||||
if (c=='>') {
|
||||
m.length*=2.0;
|
||||
redraw=2;
|
||||
}
|
||||
if (c=='<') {
|
||||
m.length/=2.0;
|
||||
redraw=2;
|
||||
}
|
||||
|
||||
// Exit
|
||||
if (c=='q' || c=='Q') {
|
||||
cpgend();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int arg=0;
|
||||
|
||||
// Initialize setup
|
||||
initialize_setup();
|
||||
|
||||
// Decode options
|
||||
while ((arg=getopt(argc,argv,"t:c:i:s:l:h"))!=-1) {
|
||||
switch (arg) {
|
||||
|
||||
case 't':
|
||||
strcpy(m.nfd,optarg);
|
||||
m.mjd=nfd2mjd(m.nfd);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
strcpy(m.tlefile,optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
get_site(atoi(optarg));
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
m.satno=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
m.length=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Read data
|
||||
read_globe();
|
||||
|
||||
// Initialize plot
|
||||
init_plot("/xs",8,0.75);
|
||||
|
||||
plot_map();
|
||||
|
||||
cpgend();
|
||||
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void read_globe(void)
|
||||
{
|
||||
int i,status;
|
||||
FILE *file;
|
||||
char filename[LIM];
|
||||
|
||||
sprintf(filename,"%s/data/globe.dat",m.datadir);
|
||||
file=fopen(filename,"r");
|
||||
|
||||
for (i=0;i<MMAX;i++) {
|
||||
status=fscanf(file,"%f %f",&glb.b[i],&glb.l[i]);
|
||||
}
|
||||
fclose(file);
|
||||
glb.n=MMAX;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void plot_globe(void)
|
||||
{
|
||||
int i,flag;
|
||||
|
||||
for (i=0,flag=0;i<glb.n;i++) {
|
||||
if (glb.b[i]==9999.0) {
|
||||
flag=0;
|
||||
continue;
|
||||
}
|
||||
if (flag==0) {
|
||||
cpgmove(glb.l[i],glb.b[i]);
|
||||
flag=1;
|
||||
} else {
|
||||
cpgdraw(glb.l[i],glb.b[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize setup
|
||||
void initialize_setup(void)
|
||||
{
|
||||
char *env;
|
||||
|
||||
// Default parameters
|
||||
m.satno=0;
|
||||
m.timezone=0.0;
|
||||
m.length=60;
|
||||
nfd_now(m.nfd);
|
||||
m.mjd=nfd2mjd(m.nfd);
|
||||
|
||||
// Default settings
|
||||
strcpy(m.observer,"Unknown");
|
||||
m.site_id=0;
|
||||
|
||||
// Get environment variables
|
||||
env=getenv("ST_DATADIR");
|
||||
if (env!=NULL) {
|
||||
strcpy(m.datadir,env);
|
||||
} else {
|
||||
printf("ST_DATADIR environment variable not found.\n");
|
||||
}
|
||||
env=getenv("ST_COSPAR");
|
||||
if (env!=NULL) {
|
||||
get_site(atoi(env));
|
||||
} else {
|
||||
printf("ST_COSPAR environment variable not found.\n");
|
||||
}
|
||||
env=getenv("ST_TLEDIR");
|
||||
if (env!=NULL) {
|
||||
strcpy(m.tledir,env);
|
||||
} else {
|
||||
printf("ST_TLEDIR environment variable not found.\n");
|
||||
}
|
||||
sprintf(m.tlefile,"%s/classfd.tle",m.tledir);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Present nfd
|
||||
void nfd_now(char *s)
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm *ptm;
|
||||
|
||||
// Get UTC time
|
||||
time(&rawtime);
|
||||
ptm=gmtime(&rawtime);
|
||||
|
||||
sprintf(s,"%04d-%02d-%02dT%02d:%02d:%02d",ptm->tm_year+1900,ptm->tm_mon+1,ptm->tm_mday,ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// nfd2mjd
|
||||
double nfd2mjd(char *date)
|
||||
{
|
||||
int year,month,day,hour,min,sec;
|
||||
double mjd,dday;
|
||||
|
||||
sscanf(date,"%04d-%02d-%02dT%02d:%02d:%02d",&year,&month,&day,&hour,&min,&sec);
|
||||
dday=day+hour/24.0+min/1440.0+sec/86400.0;
|
||||
|
||||
mjd=date2mjd(year,month,dday);
|
||||
|
||||
return mjd;
|
||||
}
|
||||
|
||||
void usage()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute Date from Julian Day
|
||||
void mjd2date(double mjd,char *date,int length)
|
||||
{
|
||||
double f,jd,dday;
|
||||
int z,alpha,a,b,c,d,e;
|
||||
int year,month,day,hour,min;
|
||||
float sec,x;
|
||||
|
||||
jd=mjd+2400000.5;
|
||||
jd+=0.5;
|
||||
|
||||
z=floor(jd);
|
||||
f=fmod(jd,1.);
|
||||
|
||||
if (z<2299161)
|
||||
a=z;
|
||||
else {
|
||||
alpha=floor((z-1867216.25)/36524.25);
|
||||
a=z+1+alpha-floor(alpha/4.);
|
||||
}
|
||||
b=a+1524;
|
||||
c=floor((b-122.1)/365.25);
|
||||
d=floor(365.25*c);
|
||||
e=floor((b-d)/30.6001);
|
||||
|
||||
dday=b-d-floor(30.6001*e)+f;
|
||||
if (e<14)
|
||||
month=e-1;
|
||||
else
|
||||
month=e-13;
|
||||
|
||||
if (month>2)
|
||||
year=c-4716;
|
||||
else
|
||||
year=c-4715;
|
||||
|
||||
day=(int) floor(dday);
|
||||
x=24.0*(dday-day);
|
||||
x=3600.*fabs(x);
|
||||
sec=fmod(x,60.);
|
||||
x=(x-sec)/60.;
|
||||
min=fmod(x,60.);
|
||||
x=(x-min)/60.;
|
||||
hour=x;
|
||||
sec=floor(1000.0*sec)/1000.0;
|
||||
|
||||
if (length==3)
|
||||
sprintf(date,"%04d-%02d-%02dT%02d:%02d:%06.3f",year,month,day,hour,min,sec);
|
||||
else if (length==0)
|
||||
sprintf(date,"%04d-%02d-%02dT%02d:%02d:%02.0f",year,month,day,hour,min,sec);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute Julian Day from Date
|
||||
double date2mjd(int year,int month,double day)
|
||||
{
|
||||
int a,b;
|
||||
double jd;
|
||||
|
||||
if (month<3) {
|
||||
year--;
|
||||
month+=12;
|
||||
}
|
||||
|
||||
a=floor(year/100.);
|
||||
b=2.-a+floor(a/4.);
|
||||
|
||||
if (year<1582) b=0;
|
||||
if (year==1582 && month<10) b=0;
|
||||
if (year==1852 && month==10 && day<=4) b=0;
|
||||
|
||||
jd=floor(365.25*(year+4716))+floor(30.6001*(month+1))+day+b-1524.5;
|
||||
|
||||
return jd-2400000.5;
|
||||
}
|
||||
|
||||
// Solar position
|
||||
void sunpos_xyz(double mjd,xyz_t *pos,double *ra,double *de)
|
||||
{
|
||||
double jd,t,l0,m,e,c,r;
|
||||
double n,s,ecl;
|
||||
|
||||
jd=mjd+2400000.5;
|
||||
t=(jd-2451545.0)/36525.0;
|
||||
l0=modulo(280.46646+t*(36000.76983+t*0.0003032),360.0)*D2R;
|
||||
m=modulo(357.52911+t*(35999.05029-t*0.0001537),360.0)*D2R;
|
||||
e=0.016708634+t*(-0.000042037-t*0.0000001267);
|
||||
c=(1.914602+t*(-0.004817-t*0.000014))*sin(m)*D2R;
|
||||
c+=(0.019993-0.000101*t)*sin(2.0*m)*D2R;
|
||||
c+=0.000289*sin(3.0*m)*D2R;
|
||||
|
||||
r=1.000001018*(1.0-e*e)/(1.0+e*cos(m+c));
|
||||
n=modulo(125.04-1934.136*t,360.0)*D2R;
|
||||
s=l0+c+(-0.00569-0.00478*sin(n))*D2R;
|
||||
ecl=(23.43929111+(-46.8150*t-0.00059*t*t+0.001813*t*t*t)/3600.0+0.00256*cos(n))*D2R;
|
||||
|
||||
*ra=atan2(cos(ecl)*sin(s),cos(s))*R2D;
|
||||
*de=asin(sin(ecl)*sin(s))*R2D;
|
||||
|
||||
pos->x=r*cos(*de*D2R)*cos(*ra*D2R)*XKMPAU;
|
||||
pos->y=r*cos(*de*D2R)*sin(*ra*D2R)*XKMPAU;
|
||||
pos->z=r*sin(*de*D2R)*XKMPAU;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double gmst(double mjd)
|
||||
{
|
||||
double t,gmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
gmst=modulo(280.46061837+360.98564736629*(mjd-51544.5)+t*t*(0.000387933-t/38710000),360.0);
|
||||
|
||||
return gmst;
|
||||
}
|
||||
|
||||
// Greenwich Mean Sidereal Time
|
||||
double dgmst(double mjd)
|
||||
{
|
||||
double t,dgmst;
|
||||
|
||||
t=(mjd-51544.5)/36525.0;
|
||||
|
||||
dgmst=360.98564736629+t*(0.000387933-t/38710000);
|
||||
|
||||
return dgmst;
|
||||
}
|
||||
|
||||
// Return x modulo y [0,y)
|
||||
double modulo(double x,double y)
|
||||
{
|
||||
x=fmod(x,y);
|
||||
if (x<0.0) x+=y;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
// rotate vector
|
||||
void rotate(int axis,float angle,float *x,float *y,float *z)
|
||||
{
|
||||
float xx,yy,zz;
|
||||
float ca,sa;
|
||||
|
||||
ca=cos(angle*D2R);
|
||||
sa=sin(angle*D2R);
|
||||
|
||||
if (axis==0) {
|
||||
xx= *x;
|
||||
yy= *y*ca- *z*sa;
|
||||
zz= *z*ca+ *y*sa;
|
||||
}
|
||||
if (axis==1) {
|
||||
xx= *x*ca- *z*sa;
|
||||
yy= *y;
|
||||
zz= *z*ca+ *x*sa;
|
||||
}
|
||||
if (axis==2) {
|
||||
xx= *x*ca- *y*sa;
|
||||
yy= *y*ca+ *x*sa;
|
||||
zz= *z;
|
||||
}
|
||||
|
||||
*x=xx;
|
||||
*y=yy;
|
||||
*z=zz;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get observing site
|
||||
void get_site(int site_id)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
int id;
|
||||
double lat,lng;
|
||||
float alt;
|
||||
char abbrev[3],observer[64];
|
||||
char filename[LIM];
|
||||
|
||||
sprintf(filename,"%s/data/sites.txt",m.datadir);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
printf("File with site information not found!\n");
|
||||
return;
|
||||
}
|
||||
while (fgets(line,LIM,file)!=NULL) {
|
||||
// Skip
|
||||
if (strstr(line,"#")!=NULL)
|
||||
continue;
|
||||
|
||||
// Strip newline
|
||||
line[strlen(line)-1]='\0';
|
||||
|
||||
// Read data
|
||||
sscanf(line,"%4d %2s %lf %lf %f",
|
||||
&id,abbrev,&lat,&lng,&alt);
|
||||
strcpy(observer,line+38);
|
||||
|
||||
// Change to km
|
||||
alt/=1000.0;
|
||||
|
||||
if (id==site_id) {
|
||||
m.lat=lat;
|
||||
m.lng=lng;
|
||||
m.alt=alt;
|
||||
m.site_id=id;
|
||||
strcpy(m.observer,observer);
|
||||
}
|
||||
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,221 @@
|
|||
/* > satutl.c
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "sgdp4h.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
static char *st_start(char *buf);
|
||||
static long i_read(char *str, int start, int stop);
|
||||
static double d_read(char *str, int start, int stop);
|
||||
|
||||
/* ====================================================================
|
||||
Read a string from key board, remove CR/LF etc.
|
||||
==================================================================== */
|
||||
|
||||
void read_kb(char *buf)
|
||||
{
|
||||
int ii;
|
||||
|
||||
fgets(buf, ST_SIZE-1, stdin);
|
||||
|
||||
/* Remove the CR/LF etc. */
|
||||
for(ii = 0; ii < ST_SIZE; ii++)
|
||||
{
|
||||
if(buf[ii] == '\r' || buf[ii] == '\n')
|
||||
{
|
||||
buf[ii] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ====================================================================
|
||||
Read orbit parameters for "satno" in file "filename", return -1 if
|
||||
failed to find the corresponding data. Call with satno = 0 to get the
|
||||
next elements of whatever sort.
|
||||
==================================================================== */
|
||||
|
||||
int read_twoline(FILE *fp, long search_satno, orbit_t *orb)
|
||||
{
|
||||
static char search[ST_SIZE];
|
||||
static char line1[ST_SIZE];
|
||||
static char line2[ST_SIZE];
|
||||
char *st1, *st2;
|
||||
int found;
|
||||
double bm, bx;
|
||||
|
||||
st1 = line1;
|
||||
st2 = line2;
|
||||
|
||||
do {
|
||||
if(fgets(line1, ST_SIZE-1, fp) == NULL) return -1;
|
||||
st1 = st_start(line1);
|
||||
} while(st1[0] != '1');
|
||||
|
||||
if(search_satno > 0)
|
||||
{
|
||||
found = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = 1;
|
||||
search_satno = atol(st1+2);
|
||||
}
|
||||
|
||||
sprintf(search, "1 %05ld", search_satno);
|
||||
|
||||
do {
|
||||
st1 = st_start(line1);
|
||||
if(strncmp(st1, search, 7) == 0)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
} while(fgets(line1, ST_SIZE-1, fp) != NULL);
|
||||
|
||||
|
||||
sprintf(search, "2 %05ld", search_satno);
|
||||
|
||||
if(found)
|
||||
{
|
||||
fgets(line2, ST_SIZE-1, fp);
|
||||
st2 = st_start(line2);
|
||||
}
|
||||
|
||||
if(!found || strncmp(st2, search, 7) != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
orb->ep_year = (int)i_read(st1, 19, 20);
|
||||
|
||||
if(orb->ep_year < 57) orb->ep_year += 2000;
|
||||
else orb->ep_year += 1900;
|
||||
|
||||
orb->ep_day = d_read(st1, 21, 32);
|
||||
|
||||
bm = d_read(st1, 54, 59) * 1.0e-5;
|
||||
bx = d_read(st1, 60, 61);
|
||||
orb->bstar = bm * pow(10.0, bx);
|
||||
|
||||
orb->eqinc = RAD(d_read(st2, 9, 16));
|
||||
orb->ascn = RAD(d_read(st2, 18, 25));
|
||||
orb->ecc = d_read(st2, 27, 33) * 1.0e-7;
|
||||
orb->argp = RAD(d_read(st2, 35, 42));
|
||||
orb->mnan = RAD(d_read(st2, 44, 51));
|
||||
orb->rev = d_read(st2, 53, 63);
|
||||
orb->norb = i_read(st2, 64, 68);
|
||||
|
||||
orb->satno = search_satno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Locate the first non-white space character, return location.
|
||||
================================================================== */
|
||||
|
||||
static char *st_start(char *buf)
|
||||
{
|
||||
if(buf == NULL) return buf;
|
||||
|
||||
while(*buf != '\0' && isspace(*buf)) buf++;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Mimick the FORTRAN formatted read (assumes array starts at 1), copy
|
||||
characters to buffer then convert.
|
||||
================================================================== */
|
||||
|
||||
static long i_read(char *str, int start, int stop)
|
||||
{
|
||||
long itmp=0;
|
||||
char *buf, *tmp;
|
||||
int ii;
|
||||
|
||||
start--; /* 'C' arrays start at 0 */
|
||||
stop--;
|
||||
|
||||
tmp = buf = (char *)vector(stop-start+2, sizeof(char));
|
||||
|
||||
for(ii = start; ii <= stop; ii++)
|
||||
{
|
||||
*tmp++ = str[ii]; /* Copy the characters. */
|
||||
}
|
||||
*tmp = '\0'; /* NUL terminate */
|
||||
|
||||
itmp = atol(buf); /* Convert to long integer. */
|
||||
free(buf);
|
||||
|
||||
return itmp;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Mimick the FORTRAN formatted read (assumes array starts at 1), copy
|
||||
characters to buffer then convert.
|
||||
================================================================== */
|
||||
|
||||
static double d_read(char *str, int start, int stop)
|
||||
{
|
||||
double dtmp=0;
|
||||
char *buf, *tmp;
|
||||
int ii;
|
||||
|
||||
start--;
|
||||
stop--;
|
||||
|
||||
tmp = buf = (char *)vector(stop-start+2, sizeof(char));
|
||||
|
||||
for(ii = start; ii <= stop; ii++)
|
||||
{
|
||||
*tmp++ = str[ii]; /* Copy the characters. */
|
||||
}
|
||||
*tmp = '\0'; /* NUL terminate */
|
||||
|
||||
dtmp = atof(buf); /* Convert to long integer. */
|
||||
free(buf);
|
||||
|
||||
return dtmp;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Allocate and check an all-zero array of memory (storage vector).
|
||||
================================================================== */
|
||||
|
||||
void *vector(size_t num, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
ptr = calloc(num, size);
|
||||
if(ptr == NULL)
|
||||
{
|
||||
fatal_error("vector: Allocation failed %u * %u", num, size);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* ==================================================================
|
||||
Print out orbital parameters.
|
||||
================================================================== */
|
||||
|
||||
void print_orb(orbit_t *orb)
|
||||
{
|
||||
printf("# Satellite ID = %ld\n", (long)orb->satno);
|
||||
printf("# Epoch year = %d day = %.8f\n", orb->ep_year, orb->ep_day);
|
||||
printf("# Eccentricity = %.7f\n", orb->ecc);
|
||||
printf("# Equatorial inclination = %.4f deg\n", DEG(orb->eqinc));
|
||||
printf("# Argument of perigee = %.4f deg\n", DEG(orb->argp));
|
||||
printf("# Mean anomaly = %.4f deg\n", DEG(orb->mnan));
|
||||
printf("# Right Ascension of Ascending Node = %.4f deg\n", DEG(orb->ascn));
|
||||
printf("# Mean Motion (number of rev/day) = %.8f\n", orb->rev);
|
||||
printf("# BSTAR drag = %.4e\n", orb->bstar);
|
||||
printf("# Orbit number = %ld\n", orb->norb);
|
||||
}
|
||||
|
||||
/* ====================================================================== */
|
|
@ -0,0 +1,30 @@
|
|||
/* > satutl.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SATUTL_H
|
||||
#define _SATUTL_H
|
||||
|
||||
#define ST_SIZE 256
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** satutl.c **/
|
||||
void read_kb(char *buf);
|
||||
int read_twoline(FILE *fp, long satno, orbit_t *orb);
|
||||
void *vector(size_t num, size_t size);
|
||||
void print_orb(orbit_t *orb);
|
||||
|
||||
/** aries.c **/
|
||||
double gha_aries(double jd);
|
||||
|
||||
/** ferror.c **/
|
||||
void fatal_error(const char *format, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SATUTL_H */
|
|
@ -0,0 +1,828 @@
|
|||
/* > sgdp4.c
|
||||
*
|
||||
* 1.00 around 1980 - Felix R. Hoots & Ronald L. Roehrich, from original
|
||||
* SDP4.FOR and SGP4.FOR
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* Made famous by the spacetrack report No.3:
|
||||
* "Models for Propogation of NORAD Element Sets"
|
||||
* Edited and subsequently distributed by Dr. T. S. Kelso.
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* This conversion by:
|
||||
* Paul S. Crawford and Andrew R. Brooks
|
||||
* Dundee University
|
||||
*
|
||||
* NOTE !
|
||||
* This code is supplied "as is" and without warranty of any sort.
|
||||
*
|
||||
* (c) 1994-2004, Paul Crawford, Andrew Brooks
|
||||
*
|
||||
************************************************************************
|
||||
*
|
||||
* 1.07 arb Oct 1994 - Transcribed by arb Oct 1994 into 'C', then
|
||||
* modified to fit Dundee systems by psc.
|
||||
*
|
||||
* 1.08 psc Mon Nov 7 1994 - replaced original satpos.c with SGP4 model.
|
||||
*
|
||||
* 1.09 psc Wed Nov 9 1994 - Corrected a few minor translation errors after
|
||||
* testing with example two-line elements.
|
||||
*
|
||||
* 1.10 psc Mon Nov 21 1994 - A few optimising tweeks.
|
||||
*
|
||||
* 1.11 psc Wed Nov 30 1994 - No longer uses eloset() and minor error in the
|
||||
* SGP4 code corrected.
|
||||
*
|
||||
* 2.00 psc Tue Dec 13 1994 - arb discovered the archive.afit.af.mil FTP site
|
||||
* with the original FORTRAN code in machine form.
|
||||
* Tidied up and added support for the SDP4 model.
|
||||
*
|
||||
* 2.01 psc Fri Dec 23 1994 - Tested out the combined SGP4/SDP4 code against
|
||||
* the original FORTRAN versions.
|
||||
*
|
||||
* 2.02 psc Mon Jan 02 1995 - Few more tweeks and tidied up the
|
||||
* doccumentation for more general use.
|
||||
*
|
||||
* 3.00 psc Mon May 29 1995 - Cleaned up for general use & distrabution (to
|
||||
* remove Dundee specific features).
|
||||
*
|
||||
* 3.01 psc Mon Jan 12 2004 - Minor bug fix for day calculation.
|
||||
*
|
||||
* 3.02 psc Mon Jul 10 2006 - Added if(rk < (real)1.0) test for sub-orbital decay.
|
||||
*
|
||||
* 3.03 psc Sat Aug 05 2006 - Added trap for divide-by-zero when calculating xlcof.
|
||||
*
|
||||
*/
|
||||
|
||||
static const char SCCSid[] = "@(#)sgdp4.c 3.03 (C) 1995 psc SatLib: Orbital Model";
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ================ single / double precision fix-ups =============== */
|
||||
|
||||
#include "sgdp4h.h"
|
||||
|
||||
#define ECC_ZERO ((real)0.0) /* Zero eccentricity case ? */
|
||||
#define ECC_ALL ((real)1.0e-4) /* For all drag terms in GSFC case. */
|
||||
#define ECC_EPS ((real)1.0e-6) /* Too low for computing further drops. */
|
||||
#define ECC_LIMIT_LOW ((real)-1.0e-3) /* Exit point for serious decaying of orbits. */
|
||||
#define ECC_LIMIT_HIGH ((real)(1.0 - ECC_EPS)) /* Too close to 1 */
|
||||
|
||||
#define EPS_COSIO (1.5e-12) /* Minimum divisor allowed for (...)/(1+cos(IO)) */
|
||||
|
||||
#define TOTHRD (2.0/3.0)
|
||||
|
||||
#if defined( SGDP4_SNGL ) || 0
|
||||
#define NR_EPS ((real)(1.0e-6)) /* Minimum ~1e-6 min for float. */
|
||||
#else
|
||||
#define NR_EPS ((real)(1.0e-12)) /* Minimum ~1e-14 for double. */
|
||||
//#define NR_EPS ((real)(1.0e-14)) /* Minimum ~1e-14 for double. */
|
||||
//#define NR_EPS ((real)(1.0e-8)) /* Minimum ~1e-14 for double. */
|
||||
#endif
|
||||
|
||||
#define Q0 ((real)120.0)
|
||||
#define S0 ((real)78.0)
|
||||
#define XJ2 ((real)1.082616e-3)
|
||||
#define XJ3 ((real)-2.53881e-6)
|
||||
#define XJ4 ((real)-1.65597e-6)
|
||||
#define XKMPER (6378.135) /* Km per earth radii */
|
||||
#define XMNPDA (1440.0) /* Minutes per day */
|
||||
#define AE (1.0) /* Earth radius in "chosen units". */
|
||||
|
||||
#if 0
|
||||
/* Original code constants. */
|
||||
#define XKE (0.743669161e-1)
|
||||
#define CK2 ((real)5.413080e-4) /* (0.5 * XJ2 * AE * AE) */
|
||||
#define CK4 ((real)0.62098875e-6) /* (-0.375 * XJ4 * AE * AE * AE * AE) */
|
||||
#define QOMS2T ((real)1.88027916e-9) /* (pow((Q0 - S0)*AE/XKMPER, 4.0)) */
|
||||
#define KS ((real)1.01222928) /* (AE * (1.0 + S0/XKMPER)) */
|
||||
#else
|
||||
/* GSFC improved coeficient resolution. */
|
||||
#define XKE ((real)7.43669161331734132e-2)
|
||||
#define CK2 ((real)(0.5 * XJ2 * AE * AE))
|
||||
#define CK4 ((real)(-0.375 * XJ4 * AE * AE * AE * AE))
|
||||
#define QOMS2T ((real)1.880279159015270643865e-9) /* (pow((Q0 - S0)*AE/XKMPER, 4.0)) */
|
||||
#define KS ((real)(AE * (1.0 + S0/XKMPER)))
|
||||
#endif
|
||||
static const real a3ovk2 = (real)(-XJ3 / CK2 * (AE * AE * AE));
|
||||
|
||||
/* ================= Copy of the orbital elements ==================== */
|
||||
|
||||
static double xno; /* Mean motion (rad/min) */
|
||||
static real xmo; /* Mean "mean anomaly" at epoch (rad). */
|
||||
static real eo; /* Eccentricity. */
|
||||
static real xincl; /* Equatorial inclination (rad). */
|
||||
static real omegao; /* Mean argument of perigee at epoch (rad). */
|
||||
static real xnodeo; /* Mean longitude of ascending node (rad, east). */
|
||||
static real bstar; /* Drag term. */
|
||||
|
||||
double SGDP4_jd0; /* Julian Day for epoch (available to outside functions. */
|
||||
|
||||
/* ================== Local "global" variables for SGP4 ================= */
|
||||
|
||||
static int imode = SGDP4_NOT_INIT;
|
||||
static real sinIO, cosIO, sinXMO, cosXMO;
|
||||
static real c1, c2, c3, c4, c5, d2, d3, d4;
|
||||
static real omgcof, xmcof, xlcof, aycof;
|
||||
static real t2cof, t3cof, t4cof, t5cof;
|
||||
static real xnodcf, delmo, x7thm1, x3thm1, x1mth2;
|
||||
static real aodp, eta, omgdot, xnodot;
|
||||
static double xnodp, xmdot;
|
||||
|
||||
static long Isat=0; /* 16-bit compilers need 'long' integer for higher space catalogue numbers. */
|
||||
double perigee, period, apogee;
|
||||
|
||||
long Icount = 0;
|
||||
int MaxNR=0;
|
||||
extern int Set_LS_zero; /* From deep.c */
|
||||
|
||||
/* =======================================================================
|
||||
The init_sgdp4() function passes all of the required orbital elements to
|
||||
the sgdp4() function together with the pre-calculated constants. There is
|
||||
some basic error traps and the detemination of the orbital model is made.
|
||||
For near-earth satellites (xnodp < 225 minutes according to the NORAD
|
||||
classification) the SGP4 model is used, with truncated terms for low
|
||||
perigee heights when the drag terms are high. For deep-space satellites
|
||||
the SDP4 model is used and the deep-space terms initialised (a slow
|
||||
process). For orbits with an eccentricity of less than ECC_EPS the model
|
||||
reverts to a very basic circular model. This is not physically meaningfull
|
||||
but such a circluar orbit is not either! It is fast though.
|
||||
Callinr arguments:
|
||||
|
||||
orb : Input, structure with the orbital elements from NORAD 2-line
|
||||
element data in radian form.
|
||||
|
||||
The return value indicates the orbital model used.
|
||||
======================================================================= */
|
||||
|
||||
int init_sgdp4(orbit_t *orb)
|
||||
{
|
||||
LOCAL_REAL theta2, theta4, xhdot1, x1m5th;
|
||||
LOCAL_REAL s4, del1, del0;
|
||||
LOCAL_REAL betao, betao2, coef, coef1;
|
||||
LOCAL_REAL etasq, eeta, qoms24;
|
||||
LOCAL_REAL pinvsq, tsi, psisq, c1sq;
|
||||
LOCAL_DOUBLE a0, a1, epoch;
|
||||
real temp0, temp1, temp2, temp3;
|
||||
long iday, iyear;
|
||||
|
||||
/* Copy over elements. */
|
||||
/* Convert year to Gregorian with century as 1994 or 94 type ? */
|
||||
|
||||
iyear = (long)orb->ep_year;
|
||||
|
||||
if (iyear < 1960)
|
||||
{
|
||||
/* Assume 0 and 100 both refer to 2000AD */
|
||||
iyear += (iyear < 60 ? 2000 : 1900);
|
||||
}
|
||||
|
||||
if (iyear < 1901 || iyear > 2099)
|
||||
{
|
||||
fatal_error("init_sgdp4: Satellite ep_year error %ld", iyear);
|
||||
imode = SGDP4_ERROR;
|
||||
return imode;
|
||||
}
|
||||
|
||||
Isat = orb->satno;
|
||||
|
||||
/* Compute days from 1st Jan 1900 (works 1901 to 2099 only). */
|
||||
|
||||
iday = ((iyear - 1901)*1461L)/4L + 364L + 1L;
|
||||
|
||||
SGDP4_jd0 = JD1900 + iday + (orb->ep_day - 1.0); /* Julian day number. */
|
||||
|
||||
epoch = (iyear - 1900) * 1.0e3 + orb->ep_day; /* YYDDD.DDDD as from 2-line. */
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Epoch = %f SGDP4_jd0 = %f\n", epoch, SGDP4_jd0);
|
||||
#endif
|
||||
|
||||
eo = (real)orb->ecc;
|
||||
xno = (double)orb->rev * TWOPI/XMNPDA; /* Radian / unit time. */
|
||||
xincl = (real)orb->eqinc;
|
||||
xnodeo = (real)orb->ascn;
|
||||
omegao = (real)orb->argp;
|
||||
xmo = (real)orb->mnan;
|
||||
bstar = (real)orb->bstar;
|
||||
|
||||
/* A few simple error checks here. */
|
||||
|
||||
if (eo < (real)0.0 || eo > ECC_LIMIT_HIGH)
|
||||
{
|
||||
fatal_error("init_sgdp4: Eccentricity out of range for %ld (%le)", Isat, (double)eo);
|
||||
imode = SGDP4_ERROR;
|
||||
return imode;
|
||||
}
|
||||
|
||||
if (xno < 0.035*TWOPI/XMNPDA || xno > 18.0*TWOPI/XMNPDA)
|
||||
{
|
||||
fatal_error("init_sgdp4: Mean motion out of range %ld (%le)", Isat, xno);
|
||||
imode = SGDP4_ERROR;
|
||||
return imode;
|
||||
}
|
||||
|
||||
if (xincl < (real)0.0 || xincl > (real)PI)
|
||||
{
|
||||
fatal_error("init_sgdp4: Equatorial inclination out of range %ld (%le)", Isat, DEG(xincl));
|
||||
imode = SGDP4_ERROR;
|
||||
return imode;
|
||||
}
|
||||
|
||||
/* Start the initialisation. */
|
||||
|
||||
if (eo < ECC_ZERO)
|
||||
imode = SGDP4_ZERO_ECC; /* Special mode for "ideal" circular orbit. */
|
||||
else
|
||||
imode = SGDP4_NOT_INIT;
|
||||
|
||||
/*
|
||||
Recover original mean motion (xnodp) and semimajor axis (aodp)
|
||||
from input elements.
|
||||
*/
|
||||
|
||||
SINCOS(xincl, &sinIO, &cosIO);
|
||||
|
||||
theta2 = cosIO * cosIO;
|
||||
theta4 = theta2 * theta2;
|
||||
x3thm1 = (real)3.0 * theta2 - (real)1.0;
|
||||
x1mth2 = (real)1.0 - theta2;
|
||||
x7thm1 = (real)7.0 * theta2 - (real)1.0;
|
||||
|
||||
a1 = pow(XKE / xno, TOTHRD);
|
||||
betao2 = (real)1.0 - eo * eo;
|
||||
betao = SQRT(betao2);
|
||||
temp0 = (real)(1.5 * CK2) * x3thm1 / (betao * betao2);
|
||||
del1 = temp0 / (a1 * a1);
|
||||
a0 = a1 * (1.0 - del1 * (1.0/3.0 + del1 * (1.0 + del1 * 134.0/81.0)));
|
||||
del0 = temp0 / (a0 * a0);
|
||||
xnodp = xno / (1.0 + del0);
|
||||
aodp = (real)(a0 / (1.0 - del0));
|
||||
perigee = (aodp * (1.0 - eo) - AE) * XKMPER;
|
||||
apogee = (aodp * (1.0 + eo) - AE) * XKMPER;
|
||||
period = (TWOPI * 1440.0 / XMNPDA) / xnodp;
|
||||
|
||||
/*
|
||||
printf("Perigee = %lf km period = %lf min del0 = %e\n",
|
||||
perigee, period, del0);
|
||||
*/
|
||||
if (perigee <= 0.0)
|
||||
{
|
||||
fprintf(stderr, "# Satellite %ld sub-orbital (apogee = %.1f km, perigee = %.1f km)\n", Isat, apogee, perigee);
|
||||
}
|
||||
|
||||
if (imode == SGDP4_ZERO_ECC) return imode;
|
||||
|
||||
if (period >= 225.0 && Set_LS_zero < 2)
|
||||
{
|
||||
imode = SGDP4_DEEP_NORM; /* Deep-Space model(s). */
|
||||
}
|
||||
else if (perigee < 220.0)
|
||||
{
|
||||
/*
|
||||
For perigee less than 220 km the imode flag is set so the
|
||||
equations are truncated to linear variation in sqrt A and
|
||||
quadratic variation in mean anomaly. Also the c3 term, the
|
||||
delta omega term and the delta m term are dropped.
|
||||
*/
|
||||
imode = SGDP4_NEAR_SIMP; /* Near-space, simplified equations. */
|
||||
}
|
||||
else
|
||||
{
|
||||
imode = SGDP4_NEAR_NORM; /* Near-space, normal equations. */
|
||||
}
|
||||
|
||||
/* For perigee below 156 km the values of S and QOMS2T are altered */
|
||||
|
||||
if (perigee < 156.0)
|
||||
{
|
||||
s4 = (real)(perigee - 78.0);
|
||||
|
||||
if(s4 < (real)20.0)
|
||||
{
|
||||
fprintf(stderr, "# Very low s4 constant for sat %ld (perigee = %.2f)\n", Isat, perigee);
|
||||
s4 = (real)20.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "# Changing s4 constant for sat %ld (perigee = %.2f)\n", Isat, perigee);
|
||||
}
|
||||
|
||||
qoms24 = POW4((real)((120.0 - s4) * (AE / XKMPER)));
|
||||
s4 = (real)(s4 / XKMPER + AE);
|
||||
}
|
||||
else
|
||||
{
|
||||
s4 = KS;
|
||||
qoms24 = QOMS2T;
|
||||
}
|
||||
|
||||
pinvsq = (real)1.0 / (aodp * aodp * betao2 * betao2);
|
||||
tsi = (real)1.0 / (aodp - s4);
|
||||
eta = aodp * eo * tsi;
|
||||
etasq = eta * eta;
|
||||
eeta = eo * eta;
|
||||
psisq = FABS((real)1.0 - etasq);
|
||||
coef = qoms24 * POW4(tsi);
|
||||
coef1 = coef / POW(psisq, 3.5);
|
||||
|
||||
c2 = coef1 * (real)xnodp * (aodp *
|
||||
((real)1.0 + (real)1.5 * etasq + eeta * ((real)4.0 + etasq)) +
|
||||
(real)(0.75 * CK2) * tsi / psisq * x3thm1 *
|
||||
((real)8.0 + (real)3.0 * etasq * ((real)8.0 + etasq)));
|
||||
|
||||
c1 = bstar * c2;
|
||||
|
||||
c4 = (real)2.0 * (real)xnodp * coef1 * aodp * betao2 * (eta *
|
||||
((real)2.0 + (real)0.5 * etasq) + eo * ((real)0.5 + (real)2.0 *
|
||||
etasq) - (real)(2.0 * CK2) * tsi / (aodp * psisq) * ((real)-3.0 *
|
||||
x3thm1 * ((real)1.0 - (real)2.0 * eeta + etasq *
|
||||
((real)1.5 - (real)0.5 * eeta)) + (real)0.75 * x1mth2 * ((real)2.0 *
|
||||
etasq - eeta * ((real)1.0 + etasq)) * COS((real)2.0 * omegao)));
|
||||
|
||||
c5 = c3 = omgcof = (real)0.0;
|
||||
|
||||
if (imode == SGDP4_NEAR_NORM)
|
||||
{
|
||||
/* BSTAR drag terms for normal near-space 'normal' model only. */
|
||||
c5 = (real)2.0 * coef1 * aodp * betao2 *
|
||||
((real)1.0 + (real)2.75 * (etasq + eeta) + eeta * etasq);
|
||||
|
||||
if(eo > ECC_ALL)
|
||||
{
|
||||
c3 = coef * tsi * a3ovk2 * (real)xnodp * (real)AE * sinIO / eo;
|
||||
}
|
||||
|
||||
omgcof = bstar * c3 * COS(omegao);
|
||||
}
|
||||
|
||||
temp1 = (real)(3.0 * CK2) * pinvsq * (real)xnodp;
|
||||
temp2 = temp1 * CK2 * pinvsq;
|
||||
temp3 = (real)(1.25 * CK4) * pinvsq * pinvsq * (real)xnodp;
|
||||
|
||||
xmdot = xnodp + ((real)0.5 * temp1 * betao * x3thm1 + (real)0.0625 *
|
||||
temp2 * betao * ((real)13.0 - (real)78.0 * theta2 +
|
||||
(real)137.0 * theta4));
|
||||
|
||||
x1m5th = (real)1.0 - (real)5.0 * theta2;
|
||||
|
||||
omgdot = (real)-0.5 * temp1 * x1m5th + (real)0.0625 * temp2 *
|
||||
((real)7.0 - (real)114.0 * theta2 + (real)395.0 * theta4) +
|
||||
temp3 * ((real)3.0 - (real)36.0 * theta2 + (real)49.0 * theta4);
|
||||
|
||||
xhdot1 = -temp1 * cosIO;
|
||||
xnodot = xhdot1 + ((real)0.5 * temp2 * ((real)4.0 - (real)19.0 * theta2) +
|
||||
(real)2.0 * temp3 * ((real)3.0 - (real)7.0 * theta2)) * cosIO;
|
||||
|
||||
xmcof = (real)0.0;
|
||||
if(eo > ECC_ALL)
|
||||
{
|
||||
xmcof = (real)(-TOTHRD * AE) * coef * bstar / eeta;
|
||||
}
|
||||
|
||||
xnodcf = (real)3.5 * betao2 * xhdot1 * c1;
|
||||
t2cof = (real)1.5 * c1;
|
||||
|
||||
/* Check for possible divide-by-zero for X/(1+cosIO) when calculating xlcof */
|
||||
temp0 = (real)1.0 + cosIO;
|
||||
|
||||
if(fabs(temp0) < EPS_COSIO) temp0 = (real)SIGN(EPS_COSIO, temp0);
|
||||
|
||||
xlcof = (real)0.125 * a3ovk2 * sinIO *
|
||||
((real)3.0 + (real)5.0 * cosIO) / temp0;
|
||||
|
||||
aycof = (real)0.25 * a3ovk2 * sinIO;
|
||||
|
||||
SINCOS(xmo, &sinXMO, &cosXMO);
|
||||
delmo = CUBE((real)1.0 + eta * cosXMO);
|
||||
|
||||
if (imode == SGDP4_NEAR_NORM)
|
||||
{
|
||||
c1sq = c1 * c1;
|
||||
d2 = (real)4.0 * aodp * tsi * c1sq;
|
||||
temp0 = d2 * tsi * c1 / (real)3.0;
|
||||
d3 = ((real)17.0 * aodp + s4) * temp0;
|
||||
d4 = (real)0.5 * temp0 * aodp * tsi * ((real)221.0 * aodp +
|
||||
(real)31.0 * s4) * c1;
|
||||
t3cof = d2 + (real)2.0 * c1sq;
|
||||
t4cof = (real)0.25 * ((real)3.0 * d3 + c1 * ((real)12.0 * d2 +
|
||||
(real)10.0 * c1sq));
|
||||
t5cof = (real)0.2 * ((real)3.0 * d4 + (real)12.0 * c1 * d3 +
|
||||
(real)6.0 * d2 * d2 + (real)15.0 * c1sq * ((real)2.0 *
|
||||
d2 + c1sq));
|
||||
}
|
||||
else if (imode == SGDP4_DEEP_NORM)
|
||||
{
|
||||
#ifdef NO_DEEP_SPACE
|
||||
fatal_error("init_sgdp4: Deep space equations not supported");
|
||||
#else
|
||||
imode = SGDP4_dpinit(epoch, omegao, xnodeo, xmo, eo, xincl,
|
||||
aodp, xmdot, omgdot, xnodot, xnodp);
|
||||
#endif /* !NO_DEEP_SPACE */
|
||||
}
|
||||
|
||||
return imode;
|
||||
}
|
||||
|
||||
/* =======================================================================
|
||||
The sgdp4() function computes the Keplarian elements that describe the
|
||||
position and velocity of the satellite. Depending on the initialisation
|
||||
(and the compile options) the deep-space perturbations are also included
|
||||
allowing sensible predictions for most satellites. These output elements
|
||||
can be transformed to Earth Centered Inertial coordinates (X-Y-Z) and/or
|
||||
to sub-satellite latitude and longitude as required. The terms for the
|
||||
velocity solution are often not required so the 'withvel' flag can be used
|
||||
to by-pass that step as required. This function is normally called through
|
||||
another since the input 'tsince' is the time from epoch.
|
||||
Calling arguments:
|
||||
|
||||
tsince : Input, time from epoch (minutes).
|
||||
|
||||
withvel : Input, non-zero if velocity terms required.
|
||||
|
||||
kep : Output, the Keplarian position / velocity of the satellite.
|
||||
|
||||
The return value indicates the orbital mode used.
|
||||
|
||||
======================================================================= */
|
||||
|
||||
int sgdp4(double tsince, int withvel, kep_t *kep)
|
||||
{
|
||||
LOCAL_REAL rk, uk, xnodek, xinck, em, xinc;
|
||||
LOCAL_REAL xnode, delm, axn, ayn, omega;
|
||||
LOCAL_REAL capu, epw, elsq, invR, beta2, betal;
|
||||
LOCAL_REAL sinu, sin2u, cosu, cos2u;
|
||||
LOCAL_REAL a, e, r, u, pl;
|
||||
LOCAL_REAL sinEPW, cosEPW, sinOMG, cosOMG;
|
||||
LOCAL_DOUBLE xmp, xl, xlt;
|
||||
const int MAXI = 10;
|
||||
|
||||
#ifndef NO_DEEP_SPACE
|
||||
LOCAL_DOUBLE xn, xmam;
|
||||
#endif /* !NO_DEEP_SPACE */
|
||||
|
||||
real esinE, ecosE, maxnr;
|
||||
real temp0, temp1, temp2, temp3;
|
||||
real tempa, tempe, templ;
|
||||
int ii;
|
||||
|
||||
#ifdef SGDP4_SNGL
|
||||
real ts = (real)tsince;
|
||||
#else
|
||||
#define ts tsince
|
||||
#endif /* ! SGDP4_SNGL */
|
||||
|
||||
/* Update for secular gravity and atmospheric drag. */
|
||||
|
||||
em = eo;
|
||||
xinc = xincl;
|
||||
|
||||
xmp = (double)xmo + xmdot * tsince;
|
||||
xnode = xnodeo + ts * (xnodot + ts * xnodcf);
|
||||
omega = omegao + omgdot * ts;
|
||||
|
||||
switch(imode)
|
||||
{
|
||||
case SGDP4_ZERO_ECC:
|
||||
/* Not a "real" orbit but OK for fast computation searches. */
|
||||
kep->smjaxs = kep->radius = (double)aodp * XKMPER/AE;
|
||||
kep->theta = fmod(PI + xnodp * tsince, TWOPI) - PI;
|
||||
kep->eqinc = (double)xincl;
|
||||
kep->ascn = xnodeo;
|
||||
|
||||
kep->argp = 0;
|
||||
kep->ecc = 0;
|
||||
|
||||
kep->rfdotk = 0;
|
||||
if(withvel)
|
||||
kep->rfdotk = aodp * xnodp * (XKMPER/AE*XMNPDA/86400.0); /* For km/sec */
|
||||
else
|
||||
kep->rfdotk = 0;
|
||||
|
||||
return imode;
|
||||
|
||||
case SGDP4_NEAR_SIMP:
|
||||
tempa = (real)1.0 - ts * c1;
|
||||
tempe = bstar * ts * c4;
|
||||
templ = ts * ts * t2cof;
|
||||
a = aodp * tempa * tempa;
|
||||
e = em - tempe;
|
||||
xl = xmp + omega + xnode + xnodp * templ;
|
||||
break;
|
||||
|
||||
case SGDP4_NEAR_NORM:
|
||||
delm = xmcof * (CUBE((real)1.0 + eta * COS(xmp)) - delmo);
|
||||
temp0 = ts * omgcof + delm;
|
||||
xmp += (double)temp0;
|
||||
omega -= temp0;
|
||||
tempa = (real)1.0 - (ts * (c1 + ts * (d2 + ts * (d3 + ts * d4))));
|
||||
tempe = bstar * (c4 * ts + c5 * (SIN(xmp) - sinXMO));
|
||||
templ = ts * ts * (t2cof + ts * (t3cof + ts * (t4cof + ts * t5cof)));
|
||||
//xmp += (double)temp0;
|
||||
a = aodp * tempa * tempa;
|
||||
e = em - tempe;
|
||||
xl = xmp + omega + xnode + xnodp * templ;
|
||||
break;
|
||||
|
||||
#ifndef NO_DEEP_SPACE
|
||||
case SGDP4_DEEP_NORM:
|
||||
case SGDP4_DEEP_RESN:
|
||||
case SGDP4_DEEP_SYNC:
|
||||
tempa = (real)1.0 - ts * c1;
|
||||
tempe = bstar * ts * c4;
|
||||
templ = ts * ts * t2cof;
|
||||
xn = xnodp;
|
||||
|
||||
SGDP4_dpsec(&xmp, &omega, &xnode, &em, &xinc, &xn, tsince);
|
||||
|
||||
a = POW(XKE / xn, TOTHRD) * tempa * tempa;
|
||||
e = em - tempe;
|
||||
xmam = xmp + xnodp * templ;
|
||||
|
||||
SGDP4_dpper(&e, &xinc, &omega, &xnode, &xmam, tsince);
|
||||
|
||||
if (xinc < (real)0.0)
|
||||
{
|
||||
xinc = (-xinc);
|
||||
xnode += (real)PI;
|
||||
omega -= (real)PI;
|
||||
}
|
||||
|
||||
xl = xmam + omega + xnode;
|
||||
|
||||
/* Re-compute the perturbed values. */
|
||||
SINCOS(xinc, &sinIO, &cosIO);
|
||||
|
||||
{
|
||||
real theta2 = cosIO * cosIO;
|
||||
|
||||
x3thm1 = (real)3.0 * theta2 - (real)1.0;
|
||||
x1mth2 = (real)1.0 - theta2;
|
||||
x7thm1 = (real)7.0 * theta2 - (real)1.0;
|
||||
|
||||
/* Check for possible divide-by-zero for X/(1+cosIO) when calculating xlcof */
|
||||
temp0 = (real)1.0 + cosIO;
|
||||
|
||||
if(fabs(temp0) < EPS_COSIO) temp0 = (real)SIGN(EPS_COSIO, temp0);
|
||||
|
||||
xlcof = (real)0.125 * a3ovk2 * sinIO *
|
||||
((real)3.0 + (real)5.0 * cosIO) / temp0;
|
||||
|
||||
aycof = (real)0.25 * a3ovk2 * sinIO;
|
||||
}
|
||||
|
||||
break;
|
||||
#endif /* ! NO_DEEP_SPACE */
|
||||
|
||||
default:
|
||||
fatal_error("sgdp4: Orbit not initialised");
|
||||
return SGDP4_ERROR;
|
||||
}
|
||||
|
||||
if(a < (real)1.0)
|
||||
{
|
||||
fprintf(stderr, "sgdp4: Satellite %05ld crashed at %.3f (a = %.3f Earth radii)\n", Isat, ts, a);
|
||||
return SGDP4_ERROR;
|
||||
}
|
||||
|
||||
if(e < ECC_LIMIT_LOW)
|
||||
{
|
||||
fprintf(stderr, "sgdp4: Satellite %05ld modified eccentricity too low (ts = %.3f, e = %e < %e)\n", Isat, ts, e, ECC_LIMIT_LOW);
|
||||
return SGDP4_ERROR;
|
||||
}
|
||||
|
||||
if(e < ECC_EPS)
|
||||
{
|
||||
/*fprintf(stderr, "# ecc %f at %.3f for for %05ld\n", e, ts, Isat);*/
|
||||
e = ECC_EPS;
|
||||
}
|
||||
else if(e > ECC_LIMIT_HIGH)
|
||||
{
|
||||
/*fprintf(stderr, "# ecc %f at %.3f for for %05ld\n", e, ts, Isat);*/
|
||||
e = ECC_LIMIT_HIGH;
|
||||
}
|
||||
|
||||
beta2 = (real)1.0 - e * e;
|
||||
|
||||
/* Long period periodics */
|
||||
SINCOS(omega, &sinOMG, &cosOMG);
|
||||
|
||||
temp0 = (real)1.0 / (a * beta2);
|
||||
axn = e * cosOMG;
|
||||
ayn = e * sinOMG + temp0 * aycof;
|
||||
xlt = xl + temp0 * xlcof * axn;
|
||||
|
||||
elsq = axn * axn + ayn * ayn;
|
||||
if (elsq >= (real)1.0)
|
||||
{
|
||||
fprintf(stderr, "sgdp4: SQR(e) >= 1 (%.3f at tsince = %.3f for sat %05ld)\n", elsq, tsince, Isat);
|
||||
return SGDP4_ERROR;
|
||||
}
|
||||
|
||||
/* Sensibility check for N-R correction. */
|
||||
kep->ecc = sqrt(elsq);
|
||||
|
||||
/*
|
||||
* Solve Kepler's equation using Newton-Raphson root solving. Here 'capu' is
|
||||
* almost the "Mean anomaly", initialise the "Eccentric Anomaly" term 'epw'.
|
||||
* The fmod() saves reduction of angle to +/-2pi in SINCOS() and prevents
|
||||
* convergence problems.
|
||||
*
|
||||
* Later modified to support 2nd order NR method which saves roughly 1 iteration
|
||||
* for only a couple of arithmetic operations.
|
||||
*/
|
||||
|
||||
epw = capu = fmod(xlt - xnode, TWOPI);
|
||||
|
||||
maxnr = kep->ecc;
|
||||
|
||||
for(ii = 0; ii < MAXI; ii++)
|
||||
{
|
||||
double nr, f, df;
|
||||
SINCOS(epw, &sinEPW, &cosEPW);
|
||||
|
||||
ecosE = axn * cosEPW + ayn * sinEPW;
|
||||
esinE = axn * sinEPW - ayn * cosEPW;
|
||||
|
||||
f = capu - epw + esinE;
|
||||
if (fabs(f) < NR_EPS) break;
|
||||
|
||||
df = 1.0 - ecosE;
|
||||
|
||||
/* 1st order Newton-Raphson correction. */
|
||||
nr = f / df;
|
||||
|
||||
if (ii == 0 && FABS(nr) > 1.25*maxnr)
|
||||
nr = SIGN(maxnr, nr);
|
||||
#if 1
|
||||
/* 2nd order Newton-Raphson correction. */
|
||||
else
|
||||
nr = f / (df + 0.5*esinE*nr); /* f/(df - 0.5*d2f*f/df) */
|
||||
#endif
|
||||
|
||||
epw += nr; /* Newton-Raphson correction of -F/DF. */
|
||||
//if (fabs(nr) < NR_EPS) break;
|
||||
}
|
||||
|
||||
/* Short period preliminary quantities */
|
||||
temp0 = (real)1.0 - elsq;
|
||||
betal = SQRT(temp0);
|
||||
pl = a * temp0;
|
||||
r = a * ((real)1.0 - ecosE);
|
||||
invR = (real)1.0 / r;
|
||||
temp2 = a * invR;
|
||||
temp3 = (real)1.0 / ((real)1.0 + betal);
|
||||
cosu = temp2 * (cosEPW - axn + ayn * esinE * temp3);
|
||||
sinu = temp2 * (sinEPW - ayn - axn * esinE * temp3);
|
||||
u = ATAN2(sinu, cosu);
|
||||
sin2u = (real)2.0 * sinu * cosu;
|
||||
cos2u = (real)2.0 * cosu * cosu - (real)1.0;
|
||||
temp0 = (real)1.0 / pl;
|
||||
temp1 = CK2 * temp0;
|
||||
temp2 = temp1 * temp0;
|
||||
|
||||
/* Update for short term periodics to position terms. */
|
||||
|
||||
rk = r * ((real)1.0 - (real)1.5 * temp2 * betal * x3thm1) + (real)0.5 * temp1 * x1mth2 * cos2u;
|
||||
uk = u - (real)0.25 * temp2 * x7thm1 * sin2u;
|
||||
xnodek = xnode + (real)1.5 * temp2 * cosIO * sin2u;
|
||||
xinck = xinc + (real)1.5 * temp2 * cosIO * sinIO * cos2u;
|
||||
|
||||
if(rk < (real)1.0)
|
||||
{
|
||||
#if 1
|
||||
fprintf(stderr, "sgdp4: Satellite %05ld crashed at %.3f (rk = %.3f Earth radii)\n", Isat, ts, rk);
|
||||
#endif
|
||||
return SGDP4_ERROR;
|
||||
}
|
||||
|
||||
kep->radius = rk * XKMPER/AE; /* Into km */
|
||||
kep->theta = uk;
|
||||
kep->eqinc = xinck;
|
||||
kep->ascn = xnodek;
|
||||
kep->argp = omega;
|
||||
kep->smjaxs = a * XKMPER/AE;
|
||||
|
||||
/* Short period velocity terms ?. */
|
||||
if (withvel)
|
||||
{
|
||||
/* xn = XKE / pow(a, 1.5); */
|
||||
temp0 = SQRT(a);
|
||||
temp2 = (real)XKE / (a * temp0);
|
||||
|
||||
kep->rdotk = ((real)XKE * temp0 * esinE * invR -
|
||||
temp2 * temp1 * x1mth2 * sin2u) *
|
||||
(XKMPER/AE*XMNPDA/86400.0); /* Into km/sec */
|
||||
|
||||
kep->rfdotk = ((real)XKE * SQRT(pl) * invR + temp2 * temp1 *
|
||||
(x1mth2 * cos2u + (real)1.5 * x3thm1)) *
|
||||
(XKMPER/AE*XMNPDA/86400.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
kep->rdotk = kep->rfdotk = 0;
|
||||
}
|
||||
|
||||
#ifndef SGDP4_SNGL
|
||||
#undef ts
|
||||
#endif
|
||||
|
||||
return imode;
|
||||
}
|
||||
|
||||
/* ====================================================================
|
||||
|
||||
Transformation from "Kepler" type coordinates to cartesian XYZ form.
|
||||
Calling arguments:
|
||||
|
||||
K : Kepler structure as filled by sgdp4();
|
||||
|
||||
pos : XYZ structure for position.
|
||||
|
||||
vel : same for velocity.
|
||||
|
||||
==================================================================== */
|
||||
|
||||
void kep2xyz(kep_t *K, xyz_t *pos, xyz_t *vel)
|
||||
{
|
||||
real xmx, xmy;
|
||||
real ux, uy, uz, vx, vy, vz;
|
||||
real sinT, cosT, sinI, cosI, sinS, cosS;
|
||||
|
||||
/* Orientation vectors for X-Y-Z format. */
|
||||
|
||||
SINCOS((real)K->theta, &sinT, &cosT);
|
||||
SINCOS((real)K->eqinc, &sinI, &cosI);
|
||||
SINCOS((real)K->ascn, &sinS, &cosS);
|
||||
|
||||
xmx = -sinS * cosI;
|
||||
xmy = cosS * cosI;
|
||||
|
||||
ux = xmx * sinT + cosS * cosT;
|
||||
uy = xmy * sinT + sinS * cosT;
|
||||
uz = sinI * sinT;
|
||||
|
||||
/* Position and velocity */
|
||||
|
||||
if(pos != NULL)
|
||||
{
|
||||
pos->x = K->radius * ux;
|
||||
pos->y = K->radius * uy;
|
||||
pos->z = K->radius * uz;
|
||||
}
|
||||
|
||||
if(vel != NULL)
|
||||
{
|
||||
vx = xmx * cosT - cosS * sinT;
|
||||
vy = xmy * cosT - sinS * sinT;
|
||||
vz = sinI * cosT;
|
||||
|
||||
vel->x = K->rdotk * ux + K->rfdotk * vx;
|
||||
vel->y = K->rdotk * uy + K->rfdotk * vy;
|
||||
vel->z = K->rdotk * uz + K->rfdotk * vz;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ======================================================================
|
||||
Compute the satellite position and/or velocity for a given time (in the
|
||||
form of Julian day number.)
|
||||
Calling arguments are:
|
||||
|
||||
jd : Time as Julian day number.
|
||||
|
||||
pos : Pointer to posiition vector, km (NULL if not required).
|
||||
|
||||
vel : Pointer to velocity vector, km/sec (NULL if not required).
|
||||
|
||||
====================================================================== */
|
||||
|
||||
int satpos_xyz(double jd, xyz_t *pos, xyz_t *vel)
|
||||
{
|
||||
kep_t K;
|
||||
int withvel, rv;
|
||||
double tsince;
|
||||
|
||||
tsince = (jd - SGDP4_jd0) * XMNPDA;
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Tsince = %f\n", tsince);
|
||||
#endif
|
||||
|
||||
if(vel != NULL)
|
||||
withvel = 1;
|
||||
else
|
||||
withvel = 0;
|
||||
|
||||
rv = sgdp4(tsince, withvel, &K);
|
||||
|
||||
kep2xyz(&K, pos, vel);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* ==================== End of file sgdp4.c ========================== */
|
|
@ -0,0 +1,360 @@
|
|||
/* > sgdp4h.h
|
||||
*
|
||||
*
|
||||
* Paul S. Crawford and Andrew R. Brooks
|
||||
* Dundee University
|
||||
*
|
||||
* NOTE !
|
||||
* This code is supplied "as is" and without warranty of any sort.
|
||||
*
|
||||
* (c) 1994-2004, Paul Crawford, Andrew Brooks
|
||||
*
|
||||
*
|
||||
* 2.00 psc Sun May 28 1995 - Modifed for non-Dundee use.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SGDP4H_H
|
||||
#define _SGDP4H_H
|
||||
|
||||
/*
|
||||
* Set up standard system-dependent names UNIX, LINUX, RISCOS, MSDOS, WIN32
|
||||
*/
|
||||
|
||||
#if defined( unix )
|
||||
# define UNIX
|
||||
# if defined( linux ) && !defined( LINUX )
|
||||
# define LINUX
|
||||
# endif
|
||||
#elif defined( __riscos ) && !defined( RISCOS )
|
||||
# define RISCOS
|
||||
#elif !defined( MSDOS ) && !defined( WIN32 ) && !defined( __CYGWIN__ )
|
||||
# define MSDOS
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Include files
|
||||
*/
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <memory.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef UNIX
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef SUN4
|
||||
#include <memory.h>
|
||||
#endif
|
||||
|
||||
#ifdef sun
|
||||
#include <sys/time.h> /* solaris 7 has struct timeval in here */
|
||||
#include <sunmath.h> /* for sincos() which is in libsunmath */
|
||||
#endif
|
||||
|
||||
#ifdef linux
|
||||
#include <stdint.h>
|
||||
void sincos(double x, double *s, double *c); /* declared where? */
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ================= SYSTEM SPECIFIC DEFINITIONS =====================
|
||||
*/
|
||||
|
||||
/* Use INLINE keyword when declaring inline functions */
|
||||
#ifdef WIN32
|
||||
#define INLINE __inline
|
||||
#elif defined( MSDOS )
|
||||
#define INLINE
|
||||
#else
|
||||
/*UNIX?*/
|
||||
#define INLINE inline
|
||||
#endif
|
||||
|
||||
/* Sun C compiler has automatic inline and doesn't understand inline keyword */
|
||||
#ifdef __SUNPRO_C
|
||||
#undef INLINE
|
||||
#define INLINE
|
||||
#define MACROS_ARE_SAFE
|
||||
#endif
|
||||
|
||||
/* Some very common constants. */
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653589793
|
||||
#endif /* MSDOS */
|
||||
|
||||
#ifndef PI
|
||||
#define PI M_PI
|
||||
#endif
|
||||
|
||||
#define TWOPI (2.0*PI) /* Optimising compiler will deal with this! */
|
||||
#define PB2 (0.5*PI)
|
||||
#define PI180 (PI/180.0)
|
||||
|
||||
#define SOLAR_DAY (1440.0) /* Minutes per 24 hours */
|
||||
#define SIDERIAL_DAY (23.0*60.0 + 56.0 + 4.09054/60.0) /* Against stars */
|
||||
|
||||
#define EQRAD (6378.137) /* Earth radius at equator, km */
|
||||
#define LATCON (1.0/298.257) /* Latitude radius constant */
|
||||
#define ECON ((1.0-LATCON)*(1.0-LATCON))
|
||||
|
||||
#define JD1900 2415020.5 /* Julian day number for Jan 1st, 00:00 hours 1900 */
|
||||
|
||||
|
||||
/*
|
||||
* =============================== MACROS ============================
|
||||
*
|
||||
*
|
||||
* Define macro for sign transfer, double to nearest (long) integer,
|
||||
* to square an expression (not nested), and A "safe" square, uses test
|
||||
* to force correct sequence of evaluation when the macro is nested.
|
||||
*/
|
||||
|
||||
/*
|
||||
* These macros are safe since they make no assignments.
|
||||
*/
|
||||
#define SIGN(a, b) ((b) >= 0 ? fabs(a) : -fabs(a))
|
||||
/* Coordinate conversion macros */
|
||||
#define DEG(x) ((x)/PI180)
|
||||
#define RAD(x) ((x)*PI180)
|
||||
#define GEOC(x) (atan(ECON*tan(x))) /* Geographic to geocentric. */
|
||||
#define GEOG(x) (atan(tan(x)/ECON))
|
||||
|
||||
/*
|
||||
* All other compilers can have static inline functions.
|
||||
* (SQR is used badly here: do_cal.c, glat2lat.c, satpos.c, vmath.h).
|
||||
*/
|
||||
static INLINE int NINT(double a) { return (int)(a > 0 ? a+0.5 : a-0.5); }
|
||||
static INLINE long NLONG(double a) { return (long)(a > 0 ? a+0.5 : a-0.5); }
|
||||
|
||||
static INLINE double DSQR(double a) { return(a*a); }
|
||||
static INLINE float FSQR(float a) { return(a*a); }
|
||||
static INLINE int ISQR(int a) { return(a*a); }
|
||||
|
||||
static INLINE double DCUBE(double a) { return(a*a*a); }
|
||||
static INLINE float FCUBE(float a) { return(a*a*a); }
|
||||
static INLINE int ICUBE(int a) { return(a*a*a); }
|
||||
|
||||
static INLINE double DPOW4(double a) { a*=a; return(a*a); }
|
||||
static INLINE float FPOW4(float a) { a*=a; return(a*a); }
|
||||
static INLINE int IPOW4(int a) { a*=a; return(a*a); }
|
||||
|
||||
static INLINE double DMAX(double a,double b) { if (a>b) return a; else return b; }
|
||||
static INLINE float FMAX(float a, float b) { if (a>b) return a; else return b; }
|
||||
static INLINE int IMAX(int a, int b) { if (a>b) return a; else return b; }
|
||||
|
||||
static INLINE double DMIN(double a,double b) { if (a<b) return a; else return b; }
|
||||
static INLINE float FMIN(float a, float b) { if (a<b) return a; else return b; }
|
||||
static INLINE int IMIN(int a, int b) { if (a<b) return a; else return b; }
|
||||
|
||||
static INLINE double MOD2PI(double a) { a=fmod(a, TWOPI); return a < 0.0 ? a+TWOPI : a; }
|
||||
static INLINE double MOD360(double a) { a=fmod(a, 360.0); return a < 0.0 ? a+360.0 : a; }
|
||||
|
||||
/*
|
||||
* Unless you have higher than default optimisation the Sun compiler
|
||||
* would prefer to be told explicitly about inline functions after their
|
||||
* declaration.
|
||||
*/
|
||||
#if defined(__SUNPRO_C) && !defined(MACROS_ARE_SAFE)
|
||||
#pragma inline_routines(NINT, NLONG, DSQR, FSQR, ISQR, DCUBE, FCUBE, ICUBE, DPOW4, FPOW4, IPOW4)
|
||||
#pragma inline_routines(DMAX, FMAX, IMAX, DMIN, FMIN, IMIN, MOD2PI, MOD360, S_GEOC, S_GEOG)
|
||||
#endif
|
||||
|
||||
/* ==================================================================== */
|
||||
|
||||
typedef struct orbit_s
|
||||
{
|
||||
/* Add the epoch time if required. */
|
||||
|
||||
int ep_year;/* Year of epoch, e.g. 94 for 1994, 100 for 2000AD */
|
||||
double ep_day; /* Day of epoch from 00:00 Jan 1st ( = 1.0 ) */
|
||||
double rev; /* Mean motion, revolutions per day */
|
||||
double bstar; /* Drag term .*/
|
||||
double eqinc; /* Equatorial inclination, radians */
|
||||
double ecc; /* Eccentricity */
|
||||
double mnan; /* Mean anomaly at epoch from elements, radians */
|
||||
double argp; /* Argument of perigee, radians */
|
||||
double ascn; /* Right ascension (ascending node), radians */
|
||||
double smjaxs; /* Semi-major axis, km */
|
||||
long norb; /* Orbit number, for elements */
|
||||
int satno; /* Satellite number. */
|
||||
|
||||
} orbit_t;
|
||||
|
||||
typedef struct xyz_s
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
} xyz_t;
|
||||
|
||||
typedef struct kep_s
|
||||
{
|
||||
double theta; /* Angle "theta" from equatorial plane (rad) = U. */
|
||||
double ascn; /* Right ascension (rad). */
|
||||
double eqinc; /* Equatorial inclination (rad). */
|
||||
double radius; /* Radius (km). */
|
||||
double rdotk;
|
||||
double rfdotk;
|
||||
|
||||
/*
|
||||
* Following are without short-term perturbations but used to
|
||||
* speed searchs.
|
||||
*/
|
||||
|
||||
double argp; /* Argument of perigee at 'tsince' (rad). */
|
||||
double smjaxs; /* Semi-major axis at 'tsince' (km). */
|
||||
double ecc; /* Eccentricity at 'tsince'. */
|
||||
|
||||
} kep_t;
|
||||
|
||||
/* ================ Single or Double precision options. ================= */
|
||||
|
||||
#define DEFAULT_TO_SNGL 0
|
||||
|
||||
#if defined( SGDP4_SNGL ) || (DEFAULT_TO_SNGL && !defined( SGDP4_DBLE ))
|
||||
/* Single precision option. */
|
||||
typedef float real;
|
||||
#ifndef SGDP4_SNGL
|
||||
#define SGDP4_SNGL
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* Double precision option. */
|
||||
typedef double real;
|
||||
#ifndef SGDP4_DBLE
|
||||
#define SGDP4_DBLE
|
||||
#endif
|
||||
|
||||
#endif /* Single or double choice. */
|
||||
|
||||
/* Something silly ? */
|
||||
#if defined( SGDP4_SNGL ) && defined( SGDP4_DBLE )
|
||||
#error sgdp4h.h - Cannot have both single and double precision defined
|
||||
#endif
|
||||
|
||||
/* =========== Do we have sincos() functions available or not ? ======= */
|
||||
/*
|
||||
We can use the normal ANSI 'C' library functions in sincos() macros, but if
|
||||
we have sincos() functions they are much faster (25% under some tests). For
|
||||
DOS programs we use our assembly language functions using the 80387 (and
|
||||
higher) coprocessor FSINCOS instruction:
|
||||
|
||||
void sincos(double x, double *s, double *c);
|
||||
void sincosf(float x, float *s, float *c);
|
||||
|
||||
For the Sun 'C' compiler there is only the system supplied double precision
|
||||
version of these functions.
|
||||
*/
|
||||
|
||||
#ifdef MACRO_SINCOS
|
||||
#define sincos(x,s,c) {double sc__tmp=(x);\
|
||||
*(s)=sin(sc__tmp);\
|
||||
*(c)=cos(sc__tmp);}
|
||||
|
||||
#define SINCOS(x,s,c) {double sc__tmp=(double)(x);\
|
||||
*(s)=(real)sin(sc__tmp);\
|
||||
*(c)=(real)cos(sc__tmp);}
|
||||
|
||||
#elif !defined( sun )
|
||||
|
||||
/* For Microsoft C6.0 compiler, etc. */
|
||||
#ifdef SGDP4_SNGL
|
||||
#define SINCOS sincosf
|
||||
#else
|
||||
#define SINCOS sincos
|
||||
#endif /* ! SGDP4_SNGL */
|
||||
|
||||
void sincos(double, double *, double *);
|
||||
void sincosf(float, float *, float *);
|
||||
|
||||
#else
|
||||
/* Sun 'C' compiler. */
|
||||
#ifdef SGDP4_SNGL
|
||||
/* Use double function and cast results to single precision. */
|
||||
#define SINCOS(x,s,c) {double s__tmp, c__tmp;\
|
||||
sincos((double)(x), &s__tmp, &c__tmp);\
|
||||
*(s)=(real)s__tmp;\
|
||||
*(c)=(real)c__tmp);}
|
||||
#else
|
||||
#define SINCOS sincos
|
||||
#endif /* ! SGDP4_SNGL */
|
||||
#endif /* ! MACRO_SINCOS */
|
||||
|
||||
/* ================= Stack space problems ? ======================== */
|
||||
|
||||
#if !defined( MSDOS )
|
||||
/* Automatic variables, faster (?) but needs more stack space. */
|
||||
#define LOCAL_REAL real
|
||||
#define LOCAL_DOUBLE double
|
||||
#else
|
||||
/* Static variables, slower (?) but little stack space. */
|
||||
#define LOCAL_REAL static real
|
||||
#define LOCAL_DOUBLE static double
|
||||
#endif
|
||||
|
||||
/* ======== Macro fixes for float/double in math.h type functions. ===== */
|
||||
|
||||
#define SIN(x) (real)sin((double)(x))
|
||||
#define COS(x) (real)cos((double)(x))
|
||||
#define SQRT(x) (real)sqrt((double)(x))
|
||||
#define FABS(x) (real)fabs((double)(x))
|
||||
#define POW(x,y) (real)pow((double)(x), (double)(y))
|
||||
#define FMOD(x,y) (real)fmod((double)(x), (double)(y))
|
||||
#define ATAN2(x,y) (real)atan2((double)(x), (double)(y))
|
||||
|
||||
#ifdef SGDP4_SNGL
|
||||
#define CUBE FCUBE
|
||||
#define POW4 FPOW4
|
||||
#else
|
||||
#define CUBE DCUBE
|
||||
#define POW4 DPOW4
|
||||
#endif
|
||||
|
||||
/* SGDP4 function return values. */
|
||||
|
||||
#define SGDP4_ERROR (-1)
|
||||
#define SGDP4_NOT_INIT 0
|
||||
#define SGDP4_ZERO_ECC 1
|
||||
#define SGDP4_NEAR_SIMP 2
|
||||
#define SGDP4_NEAR_NORM 3
|
||||
#define SGDP4_DEEP_NORM 4
|
||||
#define SGDP4_DEEP_RESN 5
|
||||
#define SGDP4_DEEP_SYNC 6
|
||||
|
||||
#include "satutl.h"
|
||||
|
||||
/* ======================= Function prototypes ====================== */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** deep.c **/
|
||||
|
||||
int SGDP4_dpinit(double epoch, real omegao, real xnodeo, real xmo,
|
||||
real orb_eo, real orb_xincl, real aodp, double xmdot,
|
||||
real omgdot, real xnodot, double xnodp);
|
||||
|
||||
int SGDP4_dpsec(double *xll, real *omgasm, real *xnodes, real *em,
|
||||
real *xinc, double *xn, double tsince);
|
||||
|
||||
int SGDP4_dpper(real *em, real *xinc, real *omgasm, real *xnodes,
|
||||
double *xll, double tsince);
|
||||
|
||||
/** sgdp4.c **/
|
||||
|
||||
int init_sgdp4(orbit_t *orb);
|
||||
int sgdp4(double tsince, int withvel, kep_t *kep);
|
||||
void kep2xyz(kep_t *K, xyz_t *pos, xyz_t *vel);
|
||||
int satpos_xyz(double jd, xyz_t *pos, xyz_t *vel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !_SGDP4H_H */
|
|
@ -0,0 +1,28 @@
|
|||
// Creates Simplex
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
double **simplex(int n,double *a,double *da)
|
||||
{
|
||||
int i,j;
|
||||
double **p;
|
||||
|
||||
// Allocate pointers to rows
|
||||
p=(double **) malloc(sizeof(double *) * (n+1));
|
||||
|
||||
// Allocate rows and set pointers
|
||||
for (i=0;i<=n;i++)
|
||||
p[i]=(double *) malloc(sizeof(double) * (n+1)*n);
|
||||
|
||||
// Fill simplex
|
||||
for (i=0;i<=n;i++) {
|
||||
for (j=0;j<n;j++) {
|
||||
if (i<j) p[i][j]=a[j];
|
||||
if (i==j) p[i][j]=a[j]+da[j];
|
||||
if (i>j) p[i][j]=a[j]-da[j];
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <getopt.h>
|
||||
#include "sgdp4h.h"
|
||||
#include "satutl.h"
|
||||
|
||||
#define LIM 128
|
||||
#define XKMPER 6378.135 /* Km per earth radii */
|
||||
#define XMNPDA 1440.0 /* Minutes per day */
|
||||
#define AE 1.0 /* Earth radius in "chosen units". */
|
||||
#define XKE 0.743669161e-1
|
||||
#define CK2 5.413080e-4 /* (0.5 * XJ2 * AE * AE) */
|
||||
extern double SGDP4_jd0;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute Julian Day from Date
|
||||
double date2mjd(int year,int month,double day)
|
||||
{
|
||||
int a,b;
|
||||
double jd;
|
||||
|
||||
if (month<3) {
|
||||
year--;
|
||||
month+=12;
|
||||
}
|
||||
|
||||
a=floor(year/100.);
|
||||
b=2.-a+floor(a/4.);
|
||||
|
||||
if (year<1582) b=0;
|
||||
if (year==1582 && month<10) b=0;
|
||||
if (year==1852 && month==10 && day<=4) b=0;
|
||||
|
||||
jd=floor(365.25*(year+4716))+floor(30.6001*(month+1))+day+b-1524.5;
|
||||
|
||||
return jd-2400000.5;
|
||||
}
|
||||
|
||||
// DOY to MJD
|
||||
double doy2mjd(int year,double doy)
|
||||
{
|
||||
int month,k=2;
|
||||
double day;
|
||||
|
||||
if (year%4==0 && year%400!=0)
|
||||
k=1;
|
||||
|
||||
month=floor(9.0*(k+doy)/275.0+0.98);
|
||||
|
||||
if (doy<32)
|
||||
month=1;
|
||||
|
||||
day=doy-floor(275.0*month/9.0)+k*floor((month+9.0)/12.0)+30.0;
|
||||
|
||||
return date2mjd(year,month,day);
|
||||
}
|
||||
|
||||
void orbit(orbit_t orb,float *aodp,float *perigee,float *apogee,float *period)
|
||||
{
|
||||
float xno,eo,xincl;
|
||||
float a1,betao2,betao,temp0,del1,a0,del0,xnodp;
|
||||
|
||||
xno=orb.rev*2.0*M_PI/XMNPDA;
|
||||
eo=orb.ecc;
|
||||
xincl=orb.eqinc;
|
||||
|
||||
a1 = pow(XKE / xno, 2.0/3.0);
|
||||
betao2 = 1.0 - eo * eo;
|
||||
betao = sqrt(betao2);
|
||||
temp0 = (1.5 * CK2) * cos(xincl)*cos(xincl) / (betao * betao2);
|
||||
del1 = temp0 / (a1 * a1);
|
||||
a0 = a1 * (1.0 - del1 * (1.0/3.0 + del1 * (1.0 + del1 * 134.0/81.0)));
|
||||
del0 = temp0 / (a0 * a0);
|
||||
xnodp = xno / (1.0 + del0);
|
||||
*aodp = (a0 / (1.0 - del0));
|
||||
*perigee = (*aodp * (1.0 - eo) - 1) * XKMPER;
|
||||
*apogee = (*aodp * (1.0 + eo) - 1) * XKMPER;
|
||||
*period = (TWOPI * 1440.0 / XMNPDA) / xnodp;
|
||||
*aodp=(*aodp-1)*XKMPER;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int arg=0,satno=0,quiet=0;
|
||||
char tlefile[LIM];
|
||||
char line0[70],line1[70],line2[70];
|
||||
FILE *file;
|
||||
orbit_t orb;
|
||||
float aodp,perigee,apogee,period;
|
||||
int info=0;
|
||||
double mjd;
|
||||
char *env;
|
||||
|
||||
env=getenv("ST_TLEDIR");
|
||||
sprintf(tlefile,"%s/classfd.tle",env);
|
||||
|
||||
// Decode options
|
||||
while ((arg=getopt(argc,argv,"c:i:aq"))!=-1) {
|
||||
switch (arg) {
|
||||
|
||||
case 'c':
|
||||
strcpy(tlefile,optarg);
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
satno=atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
info=1;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
quiet=1;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage();
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Open file
|
||||
file=fopen(tlefile,"rb");
|
||||
if (file==NULL)
|
||||
fatal_error("File open failed for reading \"%s\"",tlefile);
|
||||
|
||||
if (info==0 && quiet==0)
|
||||
printf("SATNO YEAR DOY INCL ASCN ARGP MA ECC MM\n");
|
||||
if (info==1 && quiet==0)
|
||||
printf("SATNO SEMI PERIGEE APOGEE PERIOD ECC\n");
|
||||
|
||||
// Loop over file
|
||||
while (read_twoline(file,satno,&orb)==0) {
|
||||
orbit(orb,&aodp,&perigee,&apogee,&period);
|
||||
mjd=doy2mjd(orb.ep_year,orb.ep_day);
|
||||
if (info==0) printf("%05d %10.4lf %8.4f %8.4f %8.4f %8.4f %8.6f %8.5f\n",orb.satno,mjd,DEG(orb.eqinc),DEG(orb.ascn),DEG(orb.argp),DEG(orb.mnan),orb.ecc,orb.rev);
|
||||
if (info==1) printf("%05d %9.2f %9.2f %9.2f %8.2f %8.6f %14.8lf\n",orb.satno,aodp,perigee,apogee,period,orb.ecc,mjd);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#define LIM 128
|
||||
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
int find_satno(char *desig0)
|
||||
{
|
||||
FILE *file;
|
||||
int satno=99999,status;
|
||||
char desig[16];
|
||||
char *env,filename[LIM];
|
||||
|
||||
env=getenv("ST_DATADIR");
|
||||
sprintf(filename,"%s/data/desig.txt",env);
|
||||
file=fopen(filename,"r");
|
||||
if (file==NULL) {
|
||||
fprintf(stderr,"Designation file not found!\n");
|
||||
exit(0);
|
||||
}
|
||||
while (!feof(file)) {
|
||||
status=fscanf(file,"%d %s",&satno,desig);
|
||||
if (strcmp(desig,desig0)==0)
|
||||
break;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return satno;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
FILE *file;
|
||||
char line[LIM];
|
||||
int intidy,intido,piece,site,year,month,day,hour,min,sec,fsec,satno;
|
||||
char desig[16],pdesig[16];
|
||||
int format,epoch;
|
||||
float csec,cang,x;
|
||||
int rah,ram,rafm,ded,dem,defm;
|
||||
float tm,tx,am,ax;
|
||||
char sign;
|
||||
|
||||
file=fopen(argv[1],"r");
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
// Skip wrong lines
|
||||
if (!isdigit(line[0]))
|
||||
continue;
|
||||
// Skip short lines
|
||||
if (strlen(line)<55)
|
||||
continue;
|
||||
|
||||
// Scan line
|
||||
sscanf(line,"%02d%03d%02d%04d%02d%02d%02d%02d%02d%02d%03d",&intidy,&intido,
|
||||
&piece,
|
||||
&site,
|
||||
&year,
|
||||
&month,
|
||||
&day,
|
||||
&hour,
|
||||
&min,
|
||||
&sec,
|
||||
&fsec);
|
||||
sscanf(line+27,"%f",&csec);
|
||||
sscanf(line+33,"%1d",&format);
|
||||
if (format==2) {
|
||||
sscanf(line+34,"%02d%02d%d",&rah,&ram,&rafm);
|
||||
sscanf(line+42,"%c%02d%02d%d",&sign,&ded,&dem,&defm);
|
||||
} else if (format==3) {
|
||||
sscanf(line+34,"%02d%02d%d",&rah,&ram,&rafm);
|
||||
sscanf(line+42,"%c%02d%02d",&sign,&ded,&dem);
|
||||
}
|
||||
sscanf(line+50,"%f",&cang);
|
||||
sscanf(line+54,"%d",&epoch);
|
||||
|
||||
// Year switch
|
||||
if (year>50)
|
||||
year+=1900;
|
||||
else
|
||||
year+=2000;
|
||||
|
||||
// Format designation
|
||||
if (piece<26) {
|
||||
sprintf(desig,"%02d %03d%c",intidy,intido,piece+'A'-1);
|
||||
sprintf(pdesig,"%02d%03d%c",intidy,intido,piece+'A'-1);
|
||||
} else {
|
||||
fprintf(stderr,"Failed to understand designation!\n");
|
||||
fprintf(stderr,"%s\n",line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Test data format
|
||||
if (format==3) {
|
||||
x=dem*0.6;
|
||||
dem=(int) floor(x);
|
||||
defm=(int) (100.0*(x-dem));
|
||||
} else if (format!=2) {
|
||||
fprintf(stderr,"Angle format not implemented!\n");
|
||||
fprintf(stderr,"%s\n",line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fractional seconds
|
||||
if (fsec<10)
|
||||
fsec*=100;
|
||||
else if (fsec<100)
|
||||
fsec*=10;
|
||||
|
||||
// Time accuracy
|
||||
if (csec<10)
|
||||
csec*=0.1;
|
||||
else if (csec<100)
|
||||
csec*=0.01;
|
||||
tx=floor(log10(csec))+8;
|
||||
tm=floor(csec/pow(10.0,tx-8));
|
||||
|
||||
// angle accuracy
|
||||
if (cang<10)
|
||||
cang*=1;
|
||||
else if (cang<100)
|
||||
cang*=0.1;
|
||||
ax=floor(log10(cang))+8;
|
||||
am=floor(cang/pow(10.0,ax-8));
|
||||
|
||||
// Fractional RA
|
||||
if (rafm<10)
|
||||
rafm*=100;
|
||||
else if (rafm<100)
|
||||
rafm*=10;
|
||||
|
||||
// Fractional DE
|
||||
if (defm<10)
|
||||
defm*=10;
|
||||
else if (defm<100)
|
||||
defm*=1;
|
||||
|
||||
// Get satellite number
|
||||
satno=find_satno(pdesig);
|
||||
|
||||
// Format IOD line
|
||||
printf("%05d %s %04d G %04d%02d%02d%02d%02d%02d%03d %1.0f%1.0f %d%d ",satno,desig,site,year,month,day,hour,min,sec,fsec,tm,tx,format,epoch);
|
||||
printf("%02d%02d%03d%c%02d%02d%02d %1.0f%1.0f\n",rah,ram,rafm,sign,ded,dem,defm,am,ax);
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
// Versatile Fitting Routine
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
int OUTPUT=1; // Print output on screen (1 = yes; 0 = no)
|
||||
int ERRCOMP=0; // Set reduced Chi-Squared to unity (1 = yes; 0 = no)
|
||||
|
||||
int dsmin(double **,double *,int,double,double (*func)(double *));
|
||||
double **simplex(int,double *,double *);
|
||||
double parabolic_root(double,double,double,double);
|
||||
|
||||
// Versafit fitting routine
|
||||
//
|
||||
// Inputs:
|
||||
// m: number of datapoints
|
||||
// n: number of parameters
|
||||
// a: parameters
|
||||
// da: expected spread in parameters
|
||||
// func: function to fit (Chi-squared function)
|
||||
// dchisq difference in Chi-squared
|
||||
// tol: tolerance
|
||||
// opt: options
|
||||
// - n: no output
|
||||
void versafit(int m,int n,double *a,double *da,double (*func)(double *),double dchisq,double tol,char *opt)
|
||||
{
|
||||
int i,j,k,l,nfunk,kmax=50;
|
||||
double chisqmin;
|
||||
double *b,*db;
|
||||
double **p,*y;
|
||||
double d[2],errcomp;
|
||||
|
||||
// Decode options
|
||||
if (strchr(opt,'n')!=NULL) OUTPUT=0;
|
||||
if (strchr(opt,'e')!=NULL) ERRCOMP=1;
|
||||
|
||||
// Intialize y
|
||||
y=(double *) malloc(sizeof(double) * (n+1));
|
||||
|
||||
if (dchisq>=0.) {
|
||||
// Compute simplex and minimize function
|
||||
p=simplex(n,a,da);
|
||||
nfunk=dsmin(p,y,n,tol,func);
|
||||
|
||||
// Average parameters
|
||||
for (i=0;i<n;i++) {
|
||||
a[i]=0.;
|
||||
for (j=0;j<=n;j++)
|
||||
a[i]+=p[j][i];
|
||||
a[i]/=(double) (n+1);
|
||||
}
|
||||
|
||||
// Compute minimum
|
||||
chisqmin=func(a);
|
||||
|
||||
// Compute error compensation
|
||||
if (ERRCOMP) errcomp=sqrt(chisqmin/(double) (m-n));
|
||||
}
|
||||
|
||||
// Basic Information
|
||||
if (OUTPUT) {
|
||||
printf("VersaFIT:\n");
|
||||
if (m!=0)
|
||||
printf("Number of datapoints: %i\n",m);
|
||||
printf("Number of parameters: %i\n",n);
|
||||
printf("Chi-squared: %14.5f\n",chisqmin);
|
||||
if (m!=0)
|
||||
printf("Reduced Chi-squared: %14.5f\n",chisqmin/(double) (m-n));
|
||||
if (ERRCOMP) printf("Error compensation: %.4f\n",errcomp);
|
||||
printf("Number of iterations: %i\n",nfunk);
|
||||
|
||||
printf("\nParameters:\n");
|
||||
|
||||
// No error estimation
|
||||
if (dchisq==0.) {
|
||||
for (i=0;i<n;i++)
|
||||
printf(" a(%i): %12.5f\n",i+1,a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// With error estimation
|
||||
if (dchisq!=0.) {
|
||||
b=(double *) malloc(sizeof(double) * n);
|
||||
db=(double *) malloc(sizeof(double) * n);
|
||||
|
||||
for (i=0;i<n;i++) {
|
||||
if (da[i]!=0.) {
|
||||
for (j=0;j<n;j++) {
|
||||
b[j]=a[j];
|
||||
db[j]=da[j];
|
||||
}
|
||||
d[0]=-da[i];
|
||||
db[i]=0.;
|
||||
|
||||
for (k=0;k<kmax;k++) {
|
||||
b[i]=a[i]+d[0];
|
||||
|
||||
// Minimize
|
||||
p=simplex(n,b,db);
|
||||
nfunk+=dsmin(p,y,n,tol,func);
|
||||
|
||||
// Average parameters
|
||||
for (l=0;l<n;l++) {
|
||||
b[l]=0.;
|
||||
for (j=0;j<=n;j++)
|
||||
b[l]+=p[j][l];
|
||||
b[l]/=(double) (n+1);
|
||||
}
|
||||
d[0]=parabolic_root(d[0],func(b),chisqmin,dchisq);
|
||||
|
||||
if (fabs(chisqmin+dchisq-func(b))<tol) break;
|
||||
}
|
||||
|
||||
d[1]=-d[0];
|
||||
db[i]=0.;
|
||||
|
||||
for (k=0;k<kmax;k++) {
|
||||
b[i]=a[i]+d[1];
|
||||
|
||||
// Minimize
|
||||
p=simplex(n,b,db);
|
||||
nfunk+=dsmin(p,y,n,tol,func);
|
||||
|
||||
// Average parameters
|
||||
for (l=0;l<n;l++) {
|
||||
b[l]=0.;
|
||||
for (j=0;j<=n;j++)
|
||||
b[l]+=p[j][l];
|
||||
b[l]/=(double) (n+1);
|
||||
}
|
||||
d[1]=parabolic_root(d[1],func(b),chisqmin,dchisq);
|
||||
|
||||
if (fabs(chisqmin+dchisq-func(b))<tol) break;
|
||||
}
|
||||
da[i]=0.5*(fabs(d[0])+fabs(d[1]));
|
||||
if (ERRCOMP) da[i]*=errcomp;
|
||||
}
|
||||
}
|
||||
|
||||
if (OUTPUT)
|
||||
for (i=0;i<n;i++)
|
||||
printf(" a(%i): %12.5f +- %9.5f\n",i+1,a[i],da[i]);
|
||||
}
|
||||
if (OUTPUT) printf("\nTotal number of iterations: %i\n",nfunk);
|
||||
|
||||
// free(p);
|
||||
// free(y);
|
||||
// free(b);
|
||||
// free(db);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute root
|
||||
double parabolic_root(double x,double y,double y0,double dy)
|
||||
{
|
||||
double a;
|
||||
|
||||
if (fabs(x)<1e-9) {
|
||||
printf("Division by zero in function 'parabolic_root'\n");
|
||||
x=1e-9;
|
||||
}
|
||||
|
||||
a=(y-y0)/(x*x);
|
||||
|
||||
return sqrt(fabs(dy/a))*x/fabs(x);
|
||||
}
|
|
@ -0,0 +1,244 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "cel.h"
|
||||
#include "cpgplot.h"
|
||||
#include "qfits.h"
|
||||
|
||||
#define LIM 80
|
||||
#define NMAX 256
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
|
||||
struct image {
|
||||
char filename[64];
|
||||
int naxis1,naxis2,naxis3,nframes;
|
||||
float *zavg,*zstd,*zmax,*znum,*ztrk;
|
||||
double ra0,de0;
|
||||
float x0,y0;
|
||||
float a[3],b[3],xrms,yrms;
|
||||
double mjd;
|
||||
float *dt,exptime;
|
||||
char nfd[32];
|
||||
int cospar;
|
||||
};
|
||||
struct image read_fits(char *filename);
|
||||
void write_pgm(char *filename,struct image img);
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i;
|
||||
struct image img;
|
||||
|
||||
img=read_fits(argv[1]);
|
||||
|
||||
write_pgm("avg.pgm",img);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read fits image
|
||||
struct image read_fits(char *filename)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
struct image img;
|
||||
|
||||
// Copy filename
|
||||
strcpy(img.filename,filename);
|
||||
|
||||
// Image size
|
||||
img.naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
img.naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
img.naxis3=atoi(qfits_query_hdr(filename,"NAXIS3"));
|
||||
|
||||
// MJD
|
||||
img.mjd=(double) atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
strcpy(img.nfd,qfits_query_hdr(filename,"DATE-OBS"));
|
||||
|
||||
// COSPAR ID
|
||||
img.cospar=atoi(qfits_query_hdr(filename,"COSPAR"));
|
||||
|
||||
// Transformation
|
||||
img.mjd=atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
img.ra0=atof(qfits_query_hdr(filename,"CRVAL1"));
|
||||
img.de0=atof(qfits_query_hdr(filename,"CRVAL2"));
|
||||
img.x0=atof(qfits_query_hdr(filename,"CRPIX1"));
|
||||
img.y0=atof(qfits_query_hdr(filename,"CRPIX2"));
|
||||
img.a[0]=0.0;
|
||||
img.a[1]=3600.0*atof(qfits_query_hdr(filename,"CD1_1"));
|
||||
img.a[2]=3600.0*atof(qfits_query_hdr(filename,"CD1_2"));
|
||||
img.b[0]=0.0;
|
||||
img.b[1]=3600.0*atof(qfits_query_hdr(filename,"CD2_1"));
|
||||
img.b[2]=3600.0*atof(qfits_query_hdr(filename,"CD2_2"));
|
||||
img.xrms=3600.0*atof(qfits_query_hdr(filename,"CRRES1"));
|
||||
img.yrms=3600.0*atof(qfits_query_hdr(filename,"CRRES2"));
|
||||
img.exptime=atof(qfits_query_hdr(filename,"EXPTIME"));
|
||||
img.nframes=atoi(qfits_query_hdr(filename,"NFRAMES"));
|
||||
|
||||
// Timestamps
|
||||
img.dt=(float *) malloc(sizeof(float)*img.nframes);
|
||||
for (i=0;i<img.nframes;i++) {
|
||||
sprintf(key,"DT%04d",i);
|
||||
strcpy(val,qfits_query_hdr(filename,key));
|
||||
sscanf(val+1,"%f",&img.dt[i]);
|
||||
// img.dt[i]=atof(qfits_query_hdr(filename,key));
|
||||
}
|
||||
|
||||
// Allocate image memory
|
||||
img.zavg=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.zstd=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.zmax=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
img.znum=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
if (img.naxis3==5)
|
||||
img.ztrk=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2);
|
||||
|
||||
// Set parameters
|
||||
ql.xtnum=0;
|
||||
ql.ptype=PTYPE_FLOAT;
|
||||
ql.filename=filename;
|
||||
|
||||
// Loop over planes
|
||||
for (k=0;k<img.naxis3;k++) {
|
||||
ql.pnum=k;
|
||||
|
||||
// Initialize load
|
||||
if (qfitsloader_init(&ql) != 0)
|
||||
printf("Error initializing data loading\n");
|
||||
|
||||
// Test load
|
||||
if (qfits_loadpix(&ql) != 0)
|
||||
printf("Error loading actual data\n");
|
||||
|
||||
// Fill z array
|
||||
for (i=0,l=0;i<img.naxis1;i++) {
|
||||
for (j=0;j<img.naxis2;j++) {
|
||||
if (k==1) img.zstd[l]=ql.fbuf[l];
|
||||
if (k==2) img.zmax[l]=ql.fbuf[l];
|
||||
if (k==3) img.znum[l]=ql.fbuf[l];
|
||||
if (img.naxis3==5) {
|
||||
if (k==0) img.ztrk[l]=ql.fbuf[l];
|
||||
if (k==4) img.zavg[l]=ql.fbuf[l];
|
||||
} else {
|
||||
if (k==0) img.zavg[l]=ql.fbuf[l];
|
||||
}
|
||||
|
||||
l++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
// Write pgm file
|
||||
void write_pgm(char *filename,struct image img)
|
||||
{
|
||||
int i,j,k,l,n;
|
||||
FILE *file;
|
||||
float z,zavgmin,zavgmax,zstdmin,zstdmax,zmaxmin,zmaxmax;
|
||||
float s1,s2,avg,std;
|
||||
unsigned char *buffer;
|
||||
|
||||
n=img.naxis1*img.naxis2;
|
||||
for (j=0;j<3;j++) {
|
||||
for (i=0,s1=0.0,s2=0.0;i<n;i++) {
|
||||
if (j==0) z=img.zavg[i];
|
||||
if (j==1) z=img.zstd[i];
|
||||
if (j==2) z=img.zmax[i];
|
||||
s1+=z;
|
||||
s2+=z*z;
|
||||
}
|
||||
avg=s1/(float) n;
|
||||
std=sqrt(s2/(float) n-avg*avg);
|
||||
if (j==0) {
|
||||
zavgmin=avg-2*std;
|
||||
zavgmax=avg+3*std;
|
||||
}
|
||||
if (j==1) {
|
||||
zstdmin=avg-2*std;
|
||||
zstdmax=avg+3*std;
|
||||
}
|
||||
if (j==2) {
|
||||
zmaxmin=avg-2*std;
|
||||
zmaxmax=avg+3*std;
|
||||
}
|
||||
}
|
||||
buffer=(unsigned char *) malloc(sizeof(unsigned char)*4*n);
|
||||
|
||||
for (j=0,l=0;j<img.naxis2;j++) {
|
||||
for (i=0;i<img.naxis1;i++) {
|
||||
k=i+(img.naxis2-j-1)*img.naxis1;
|
||||
z=255.0*(img.zavg[k]-zavgmin)/(zavgmax-zavgmin);
|
||||
if (z>=255.0)
|
||||
z=255.0;
|
||||
if (z<0.0)
|
||||
z=0.0;
|
||||
buffer[l++]=(unsigned char) z;
|
||||
}
|
||||
for (i=0;i<img.naxis1;i++) {
|
||||
k=i+(img.naxis2-j-1)*img.naxis1;
|
||||
z=255.0*(img.zstd[k]-zstdmin)/(zstdmax-zstdmin);
|
||||
if (z>=255.0)
|
||||
z=255.0;
|
||||
if (z<0.0)
|
||||
z=0.0;
|
||||
buffer[l++]=(unsigned char) z;
|
||||
}
|
||||
}
|
||||
for (j=0;j<img.naxis2;j++) {
|
||||
for (i=0;i<img.naxis1;i++) {
|
||||
k=i+(img.naxis2-j-1)*img.naxis1;
|
||||
z=255*(img.zmax[k]-zmaxmin)/(zmaxmax-zmaxmin);
|
||||
if (z>=255.0)
|
||||
z=255.0;
|
||||
if (z<0.0)
|
||||
z=0.0;
|
||||
buffer[l++]=(unsigned char) z;
|
||||
}
|
||||
for (i=0;i<img.naxis1;i++) {
|
||||
k=i+(img.naxis2-j-1)*img.naxis1;
|
||||
z=img.znum[k];
|
||||
if (z>=255.0)
|
||||
z=255.0;
|
||||
if (z<0.0)
|
||||
z=0.0;
|
||||
buffer[l++]=(unsigned char) z;
|
||||
}
|
||||
}
|
||||
file=fopen(filename,"wb");
|
||||
fprintf(file,"P5\n%d %d\n255\n",2*img.naxis1,2*img.naxis2);
|
||||
fwrite(buffer,4*n,sizeof(unsigned char),file);
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Write pgm file
|
||||
void write_pgm2(char *filename,struct image img)
|
||||
{
|
||||
int i,j,k;
|
||||
FILE *file;
|
||||
float z;
|
||||
|
||||
file=fopen(filename,"w");
|
||||
fprintf(file,"P5\n# %.23s\n%d %d\n255\n",img.nfd+1,img.naxis1,img.naxis2);
|
||||
for (j=0;j<img.naxis2;j++) {
|
||||
for (i=0;i<img.naxis1;i++) {
|
||||
k=i+(img.naxis2-j-1)*img.naxis1;
|
||||
// z=255.0*(img.zavg[k]-30.0)/(60.0-30.0);
|
||||
z=img.zstd[k];
|
||||
//z=255.0*(img.ztrk[k]-30.0)/(60.0-30.0);
|
||||
if (z>255.0)
|
||||
z=255.0;
|
||||
if (z<0.0)
|
||||
z=0.0;
|
||||
fprintf(file,"%c",(char) z);
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,431 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "cel.h"
|
||||
#include "cpgplot.h"
|
||||
#include "qfits.h"
|
||||
#include <gsl/gsl_multifit.h>
|
||||
|
||||
#define LIM 256
|
||||
#define D2R M_PI/180.0
|
||||
#define R2D 180.0/M_PI
|
||||
#define NMAX 1024
|
||||
|
||||
struct catalog {
|
||||
int n;
|
||||
float x[NMAX],y[NMAX];
|
||||
double ra[NMAX],de[NMAX];
|
||||
float rx[NMAX],ry[NMAX];
|
||||
float xres[NMAX],yres[NMAX],res[NMAX];
|
||||
float xrms,yrms,rms;
|
||||
int usage[NMAX];
|
||||
};
|
||||
struct image {
|
||||
int naxis1,naxis2,nframes;
|
||||
float *zavg,*zstd,*zmax,*znum;
|
||||
double ra0,de0;
|
||||
float x0,y0;
|
||||
float a[2],b[2];
|
||||
double mjd;
|
||||
float *dt;
|
||||
};
|
||||
struct transformation {
|
||||
double ra0,de0;
|
||||
float a[3],b[3];
|
||||
float x0,y0;
|
||||
};
|
||||
int fgetline(FILE *file,char *s,int lim);
|
||||
void forward(double ra0,double de0,double ra,double de,float *x,float *y);
|
||||
void reverse(double ra0,double de0,float x,float y,double *ra,double *de);
|
||||
struct catalog read_catalog(char *filename);
|
||||
void lfit2d(float *x,float *y,float *z,int n,float *a);
|
||||
void add_fits_keywords(struct transformation t,char *filename);
|
||||
struct image read_fits(char *filename);
|
||||
|
||||
// Modify FITS keywords
|
||||
void modify_fits_keywords(struct transformation t,char *filename)
|
||||
{
|
||||
char card[FITS_LINESZ+1];
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
char com[FITS_LINESZ+1];
|
||||
|
||||
sprintf(val,"%f",t.x0);
|
||||
keytuple2str(card,"CRPIX1",val,"");
|
||||
qfits_replace_card(filename,"CRPIX1",card);
|
||||
|
||||
sprintf(val,"%f",t.y0);
|
||||
keytuple2str(card,"CRPIX2",val,"");
|
||||
qfits_replace_card(filename,"CRPIX2",card);
|
||||
|
||||
sprintf(val,"%f",t.ra0);
|
||||
keytuple2str(card,"CRVAL1",val,"");
|
||||
qfits_replace_card(filename,"CRVAL1",card);
|
||||
|
||||
sprintf(val,"%f",t.de0);
|
||||
keytuple2str(card,"CRVAL2",val,"");
|
||||
qfits_replace_card(filename,"CRVAL2",card);
|
||||
|
||||
sprintf(val,"%e",t.a[1]/3600.0);
|
||||
keytuple2str(card,"CD1_1",val,"");
|
||||
qfits_replace_card(filename,"CD1_1",card);
|
||||
|
||||
sprintf(val,"%e",t.a[2]/3600.0);
|
||||
keytuple2str(card,"CD1_2",val,"");
|
||||
qfits_replace_card(filename,"CD1_2",card);
|
||||
|
||||
sprintf(val,"%e",t.b[1]/3600.0);
|
||||
keytuple2str(card,"CD2_1",val,"");
|
||||
qfits_replace_card(filename,"CD2_1",card);
|
||||
|
||||
sprintf(val,"%e",t.b[2]/3600.0);
|
||||
keytuple2str(card,"CD2_2",val,"");
|
||||
qfits_replace_card(filename,"CD2_2",card);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc,char *argv[])
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
struct catalog c;
|
||||
struct transformation t;
|
||||
double ra0,de0;
|
||||
float rmsmin;
|
||||
float x[NMAX],y[NMAX],rx[NMAX],ry[NMAX];
|
||||
struct image img;
|
||||
char filename[128];
|
||||
|
||||
if (argc==1)
|
||||
strcpy(filename,"test.fits");
|
||||
else if (argc==2)
|
||||
strcpy(filename,argv[1]);
|
||||
|
||||
img=read_fits(filename);
|
||||
printf("files read\n");
|
||||
c=read_catalog("out.dat");
|
||||
printf("files read\n");
|
||||
|
||||
// Initial fit
|
||||
t.ra0=c.ra[0];
|
||||
t.de0=c.de[0];
|
||||
t.x0=(float) img.naxis1/2.0;
|
||||
t.y0=(float) img.naxis2/2.0;
|
||||
|
||||
for (l=0;l<10;l++) {
|
||||
for (j=0;j<5;j++) {
|
||||
// Transform
|
||||
for (i=0;i<c.n;i++)
|
||||
forward(t.ra0,t.de0,c.ra[i],c.de[i],&c.rx[i],&c.ry[i]);
|
||||
|
||||
// Select
|
||||
for (i=0,k=0;i<c.n;i++) {
|
||||
if (c.usage[i]==1) {
|
||||
x[k]=c.x[i];
|
||||
y[k]=c.y[i];
|
||||
rx[k]=c.rx[i];
|
||||
ry[k]=c.ry[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
// Fit
|
||||
lfit2d(x,y,rx,k,t.a);
|
||||
lfit2d(x,y,ry,k,t.b);
|
||||
printf("%f %f %f %f %f %f %f %f\n",t.ra0,t.de0,t.a[0],t.a[1],t.a[2],t.b[0],t.b[1],t.b[2]);
|
||||
|
||||
// Move reference point
|
||||
reverse(t.ra0,t.de0,t.a[0],t.b[0],&ra0,&de0);
|
||||
t.ra0=ra0;
|
||||
t.de0=de0;
|
||||
}
|
||||
|
||||
// Compute and plot residuals
|
||||
for (i=0,c.xrms=0.0,c.yrms=0.0,m=0;i<c.n;i++) {
|
||||
if (c.usage[i]==1) {
|
||||
c.xres[i]=c.rx[i]-(t.a[0]+t.a[1]*c.x[i]+t.a[2]*c.y[i]);
|
||||
c.yres[i]=c.ry[i]-(t.b[0]+t.b[1]*c.x[i]+t.b[2]*c.y[i]);
|
||||
printf("%12.4f %12.4f %12.4f %12.4f %10.4f %10.4f\n",c.x[i],c.y[i],c.rx[i],c.ry[i],c.xres[i],c.yres[i]);
|
||||
c.res[i]=sqrt(c.xres[i]*c.xres[i]+c.yres[i]*c.yres[i]);
|
||||
c.xrms+=c.xres[i]*c.xres[i];
|
||||
c.yrms+=c.yres[i]*c.yres[i];
|
||||
c.rms+=c.xres[i]*c.xres[i]+c.yres[i]*c.yres[i];
|
||||
m++;
|
||||
}
|
||||
}
|
||||
c.xrms=sqrt(c.xrms/(float) m);
|
||||
c.yrms=sqrt(c.yrms/(float) m);
|
||||
c.rms=sqrt(c.rms/(float) m);
|
||||
|
||||
// Deselect outliers
|
||||
for (i=0;i<c.n;i++) {
|
||||
if (c.res[i]>2*c.rms)
|
||||
c.usage[i]=0;
|
||||
}
|
||||
}
|
||||
printf("%12.8lf %10.6lf %10.6lf %8.4f %8.4f %8.4f %8.4f\n",img.mjd,t.ra0,t.de0,t.a[1],t.a[2],t.b[1],t.b[2]);
|
||||
printf("%d/%d %f %f %f\n",m,c.n,c.xrms,c.yrms,c.rms);
|
||||
|
||||
// add_fits_keywords(t,"test.fits");
|
||||
modify_fits_keywords(t,filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read a line of maximum length int lim from file FILE into string s
|
||||
int fgetline(FILE *file,char *s,int lim)
|
||||
{
|
||||
int c,i=0;
|
||||
|
||||
while (--lim > 0 && (c=fgetc(file)) != EOF && c != '\n')
|
||||
s[i++] = c;
|
||||
if (c == '\n')
|
||||
s[i++] = c;
|
||||
s[i] = '\0';
|
||||
return i;
|
||||
}
|
||||
|
||||
// Read catalog
|
||||
struct catalog read_catalog(char *filename)
|
||||
{
|
||||
int i=0;
|
||||
char line[LIM];
|
||||
FILE *file;
|
||||
struct catalog c;
|
||||
|
||||
file=fopen(filename,"r");
|
||||
while (fgetline(file,line,LIM)>0) {
|
||||
sscanf(line,"%f %f %lf %lf",&c.x[i],&c.y[i],&c.ra[i],&c.de[i]);
|
||||
c.usage[i]=1;
|
||||
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
c.n=i;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
// Get a x and y from a RA and Decl
|
||||
void forward(double ra0,double de0,double ra,double de,float *x,float *y)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="TAN";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
double rx,ry;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celfwd(pcode,ra,de,&cel,&phi,&theta,&prj,&rx,&ry)) {
|
||||
printf("Error in Projection (celfwd)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
*x=rx*3600.;
|
||||
*y=ry*3600.;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Linear 2D fit
|
||||
void lfit2d(float *x,float *y,float *z,int n,float *a)
|
||||
{
|
||||
int i,j,m;
|
||||
double chisq;
|
||||
gsl_matrix *X,*cov;
|
||||
gsl_vector *yy,*w,*c;
|
||||
|
||||
X=gsl_matrix_alloc(n,3);
|
||||
yy=gsl_vector_alloc(n);
|
||||
w=gsl_vector_alloc(n);
|
||||
|
||||
c=gsl_vector_alloc(3);
|
||||
cov=gsl_matrix_alloc(3,3);
|
||||
|
||||
// Fill matrices
|
||||
for(i=0;i<n;i++) {
|
||||
gsl_matrix_set(X,i,0,1.0);
|
||||
gsl_matrix_set(X,i,1,x[i]);
|
||||
gsl_matrix_set(X,i,2,y[i]);
|
||||
|
||||
gsl_vector_set(yy,i,z[i]);
|
||||
gsl_vector_set(w,i,1.0);
|
||||
}
|
||||
|
||||
// Do fit
|
||||
gsl_multifit_linear_workspace *work=gsl_multifit_linear_alloc(n,3);
|
||||
gsl_multifit_wlinear(X,w,yy,c,cov,&chisq,work);
|
||||
gsl_multifit_linear_free(work);
|
||||
|
||||
// Save parameters
|
||||
for (i=0;i<3;i++)
|
||||
a[i]=gsl_vector_get(c,(i));
|
||||
|
||||
gsl_matrix_free(X);
|
||||
gsl_vector_free(yy);
|
||||
gsl_vector_free(w);
|
||||
gsl_vector_free(c);
|
||||
gsl_matrix_free(cov);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Get a RA and Decl from x and y
|
||||
void reverse(double ra0,double de0,float x,float y,double *ra,double *de)
|
||||
{
|
||||
int i;
|
||||
char pcode[4]="TAN";
|
||||
double phi,theta;
|
||||
struct celprm cel;
|
||||
struct prjprm prj;
|
||||
double rx,ry;
|
||||
|
||||
rx=x/3600.;
|
||||
ry=y/3600.;
|
||||
|
||||
// Initialize Projection Parameters
|
||||
prj.flag=0;
|
||||
prj.r0=0.;
|
||||
for (i=0;i<10;prj.p[i++]=0.);
|
||||
|
||||
// Initialize Reference Angles
|
||||
cel.ref[0]=ra0;
|
||||
cel.ref[1]=de0;
|
||||
cel.ref[2]=999.;
|
||||
cel.ref[3]=999.;
|
||||
cel.flag=0.;
|
||||
|
||||
if (celset(pcode,&cel,&prj)) {
|
||||
printf("Error in Projection (celset)\n");
|
||||
return;
|
||||
} else {
|
||||
if (celrev(pcode,rx,ry,&prj,&phi,&theta,&cel,ra,de)) {
|
||||
printf("Error in Projection (celrev)\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Add FITS keywords
|
||||
void add_fits_keywords(struct transformation t,char *filename)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
int naxis1,naxis2,naxis3;
|
||||
qfits_header *qh;
|
||||
qfitsdumper qd;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
char com[FITS_LINESZ+1];
|
||||
char lin[FITS_LINESZ+1];
|
||||
FILE *file;
|
||||
float *fbuf;
|
||||
|
||||
naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
naxis3=atoi(qfits_query_hdr(filename,"NAXIS3"));
|
||||
|
||||
fbuf=malloc(sizeof(float)*naxis1*naxis2*naxis3);
|
||||
|
||||
// Read header
|
||||
qh=qfits_header_read(filename);
|
||||
|
||||
ql.xtnum=0;
|
||||
ql.ptype=PTYPE_FLOAT;
|
||||
ql.filename=filename;
|
||||
for (k=0,l=0;k<naxis3;k++) {
|
||||
ql.pnum=k;
|
||||
// Initialize load
|
||||
if (qfitsloader_init(&ql) != 0)
|
||||
printf("Error initializing data loading\n");
|
||||
|
||||
// Test load
|
||||
if (qfits_loadpix(&ql) != 0)
|
||||
printf("Error loading actual data\n");
|
||||
|
||||
for (i=0,m=0;i<naxis1;i++) {
|
||||
for (j=0;j<naxis2;j++) {
|
||||
fbuf[l]=ql.fbuf[m];
|
||||
l++;
|
||||
m++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qfits_header_add_after(qh,"MJD-OBS","CUNIT2","'deg'"," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CUNIT1","'deg'"," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CTYPE2","'DEC--TAN'"," ",NULL);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CTYPE1","'RA---TAN'"," ",NULL);
|
||||
sprintf(val,"%e",t.b[2]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD2_2",val," ",NULL);
|
||||
sprintf(val,"%e",t.b[1]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD2_1",val," ",NULL);
|
||||
sprintf(val,"%e",t.a[2]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD1_2",val," ",NULL);
|
||||
sprintf(val,"%e",t.a[1]/3600.0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CD1_1",val," ",NULL);
|
||||
sprintf(val,"%f",t.de0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRVAL2",val," ",NULL);
|
||||
sprintf(val,"%f",t.ra0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRVAL1",val," ",NULL);
|
||||
sprintf(val,"%f",t.y0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRPIX2",val," ",NULL);
|
||||
sprintf(val,"%f",t.x0);
|
||||
qfits_header_add_after(qh,"MJD-OBS","CRPIX1",val," ",NULL);
|
||||
|
||||
file=fopen(filename,"w");
|
||||
qfits_header_dump(qh,file);
|
||||
fclose(file);
|
||||
|
||||
qfits_header_destroy(qh);
|
||||
|
||||
qd.filename=filename;
|
||||
qd.npix=naxis1*naxis2*naxis3;
|
||||
qd.ptype=PTYPE_FLOAT;
|
||||
qd.fbuf=fbuf;
|
||||
qd.out_ptype=-32;
|
||||
|
||||
qfits_pixdump(&qd);
|
||||
free(fbuf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Read fits image
|
||||
struct image read_fits(char *filename)
|
||||
{
|
||||
int i,j,k,l,m;
|
||||
qfitsloader ql;
|
||||
char key[FITS_LINESZ+1];
|
||||
char val[FITS_LINESZ+1];
|
||||
struct image img;
|
||||
|
||||
// Image size
|
||||
img.naxis1=atoi(qfits_query_hdr(filename,"NAXIS1"));
|
||||
img.naxis2=atoi(qfits_query_hdr(filename,"NAXIS2"));
|
||||
|
||||
// MJD
|
||||
img.mjd=(double) atof(qfits_query_hdr(filename,"MJD-OBS"));
|
||||
|
||||
|
||||
return img;
|
||||
}
|
Loading…
Reference in New Issue