#include #include #include #include #include #include #include "qfits.h" #include "sgdp4h.h" #define LIM 80 #define MMAX 10 #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 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 point { double mjd; xyz_t obspos,sunpos; double zeta,z,theta; } p[MMAX]; struct image { char filename[64]; int naxis,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,tracked; }; struct image read_fits(char *filename); void get_site(int site_id); 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 precession_angles(double mjd0,double mjd,double *zeta,double *z,double *theta); void initialize(struct image img); 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); struct sat apparent_position(double mjd); void plot_satellites(char *tlefile,struct image img,long satno,double mjd0,float dt,int color) { int i; orbit_t orb; int imode,flag,textflag,sflag; FILE *fp=NULL,*file; xyz_t satpos,satvel; float x,y,x0,y0; char norad[7],satname[30],state[16]; float isch; char filename[128]; double dx,dy,dz,r,ra,de,d,rsun,rearth; double psun,pearth,ptot; double a,b,c; double rx,ry; 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) return; 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; // Loop over times for (flag=0,textflag=0,sflag=0,i=0;i300000) continue; // Relative to observer dx=satpos.x-p[i].obspos.x; dy=satpos.y-p[i].obspos.y; dz=satpos.z-p[i].obspos.z; // Celestial position r=sqrt(dx*dx+dy*dy+dz*dz); ra=modulo(atan2(dy,dx),2.0*M_PI); de=asin(dz/r); // Correct for precession a=cos(de)*sin(ra+p[i].zeta); b=cos(p[i].theta)*cos(de)*cos(ra+p[i].zeta)-sin(p[i].theta)*sin(de); c=sin(p[i].theta)*cos(de)*cos(ra+p[i].zeta)+cos(p[i].theta)*sin(de); ra=modulo((atan2(a,b)+p[i].z)*R2D,360.0); de=asin(c)*R2D; // Adjust for stationary camera if (img.tracked==0) ra+=gmst(img.mjd+0.5*img.exptime/86400.0)-gmst(p[i].mjd); // Check if nearby enough r=acos(sin(img.de0*D2R)*sin(de*D2R)+cos(img.de0*D2R)*cos(de*D2R)*cos((img.ra0-ra)*D2R))*R2D; if (r<90.0) forward(img.ra0,img.de0,ra,de,&rx,&ry); else continue; // Satellite position relative to the Sun dx=-satpos.x+p[i].sunpos.x; dy=-satpos.y+p[i].sunpos.y; dz=-satpos.z+p[i].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 psun=asin(696.0e3/rsun)*R2D; pearth=asin(6378.135/rearth)*R2D; ptot=acos((-dx*satpos.x-dy*satpos.y-dz*satpos.z)/(rsun*rearth))*R2D; // Visibility state if (ptot-pearth<-psun) { cpgsls(4); strcpy(state,"eclipsed"); } else if (ptot-pearth>-psun && ptot-pearthpsun) { cpgsls(1); strcpy(state,"sunlit"); sflag=1; } // Convert image position dx=rx-img.a[0]; dy=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; // Print name if in viewport if (x>0.0 && x0.0 && y2.0 || img.yrms/sy>2.0) cpgsci(2); else cpgsci(1); cpgmtxt("T",4.8,0.0,0.0,text); cpgsci(1); sprintf(text,"FoV: %.2f\\(2218)x%.2f\\(2218) Scale: %.2f''x%.2f'' pix\\u-1\\d",wx,wy,sx,sy); 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); if (img.naxis==3) cpgimag(img.zmax,img.naxis1,img.naxis2,1,img.naxis1,1,img.naxis2,zmin,zmax,tr); else cpgimag(img.zavg,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/inttles.tle",env); plot_satellites(filename,img,0,img.mjd,img.exptime,3); sprintf(filename,"%s/catalog.tle",env); plot_satellites(filename,img,0,img.mjd,img.exptime,0); sprintf(filename,"%s/jsc.txt",env); plot_satellites(filename,img,0,img.mjd,img.exptime,5); 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.naxis=atoi(qfits_query_hdr(filename,"NAXIS")); 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")); // Tracked if (qfits_query_hdr(filename,"TRACKED")!=NULL) img.tracked=atoi(qfits_query_hdr(filename,"TRACKED")); else img.tracked=0; // Transformation 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")); // Set parameters ql.xtnum=0; ql.ptype=PTYPE_FLOAT; ql.filename=filename; // Read four-frame info if (img.naxis==3) { // Number of frames img.nframes=atoi(qfits_query_hdr(filename,"NFRAMES")); // Timestamps img.dt=(float *) malloc(sizeof(float)*img.nframes); for (i=0;ix=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; } // Compute precession angles void precession_angles(double mjd0,double mjd,double *zeta,double *z,double *theta) { double t0,t; // 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; return; } // Initialize observer and sun position and precession angles void initialize(struct image img) { int i; double t; xyz_t obsvel; // Loop over points for (i=0;i