#include #include #include #include #include #include #include #include "qfits.h" #define D2R M_PI/180.0 #define R2D 180.0/M_PI #define LIM 256 struct image { char filename[64]; int naxis1,naxis2,naxis3,nframes; float *zavg,*zstd,*zmax,*znum,*zd,*zsig; int *mask; char nfd[32]; double ra0,de0; float x0,y0; float a[3],b[3],xrms,yrms; double mjd; float *dt,exptime; int cospar; }; struct selection { int state,fit; float x0,y0,x1,y1; float w,zmin,zmax; float a,ca,sa,r; float tmid,tmin,tmax,ax[2],sax[2],ay[2],say[2],chi2x,chi2y; }; struct observation { int satno,cospar; char desig[16],conditions,behavior; double mjd,ra,de; float terr,perr,tmid,tmin,tmax; char nfd[32],pos[32]; int epoch,type; char iod_line[80]; float x[3],y[3]; float ax[2],ay[2]; int state; }; struct track { float x0,y0,x1,y1,texp; int satno; } trk; int iobject=0; 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 nfd2mjd(char *date); double date2mjd(int year,int month,double day); void mjd2date(double mjd,char *date); void dec2s(double x,char *s,int type); float linear_fit(float x[],float y[],int n,float a[],float sa[]); int fgetline(FILE *file,char *s,int lim); double gmst(double mjd); double modulo(double x,double y); // Find peak float find_peak(float *z,int kx,int ky,int xmin,int xmax,int ymin,int ymax,float s,int mx,int my,float *x0,float *y0) { int i,j,k,l,i0,j0,k0,i1,j1,k1,nx,ny; int imid,jmid,imax,jmax,flag; float *d,*g,*w,*h; float sg,sgg,sgn,den,s1,s2; float hmax,havg,hstd; float x,y; printf("%d %d %d %d -> %d %d\n",xmin,xmax,ymin,ymax,kx,ky); // Select image if (xmin<0.0) xmin=0.0; if (ymin<0.0) ymin=0.0; if (xmax>=kx) xmax=kx; if (ymax>=ky) ymax=ky; nx=(int) (xmax-xmin); ny=(int) (ymax-ymin); d=(float *) malloc(sizeof(float)*nx*ny); for (i=xmin,i0=0;i %d %d\n",xmin,xmax,ymin,ymax,nx,ny); // Make kernel g=(float *) malloc(sizeof(float)*mx*my); for (i=0,imid=mx/2,jmid=my/2,sg=0.0,sgg=0.0;i=nx || j1<0 || j1>=ny) continue; k1=i1+nx*j1; h[k]+=w[k0]*d[k1]; } } h[k]/=(float) (mx*my); } } // Locate maximum for (i=mx,flag=0;ihmax) { imax=i; jmax=j; hmax=h[k]; } } } // Compute mean value for (i=mx,s1=0.0,s2=0.0;iax[i]; ay[i]=obs->ay[i]; } obs->ax[1]=(img.a[1]*ax[1]+img.a[2]*ay[1])/3600.0; obs->ay[1]=(img.b[1]*ax[1]+img.b[2]*ay[1])/3600.0; // Get time k=(int) x + img.naxis1*(int) y; iframe=(int) img.znum[k]; if (tmid<0.0) dt=img.dt[iframe]; else dt=tmid; mjd=nfd2mjd(img.nfd)+(double) dt/86400.0; mjd2date(mjd,nfd); obs->mjd=mjd; // Correct for motion mjd1=img.mjd+0.5*(double) img.exptime/86400.0; dra=gmst(mjd)-gmst(mjd1); ra+=dra; // Get RA/Dec dec2s(ra/15.0,sra,0); dec2s(de,sde,1); obs->ra=ra; obs->de=de; // Copy strcpy(obs->nfd,nfd); sprintf(obs->pos,"%s%s",sra,sde); return; } void compute_cuts(float *z,int *mask,int n,float *zmin,float *zmax,float lcut,float hcut) { int i,m; double s1,s2; double avg,std; for (i=0,s1=0.0,s2=0.0,m=0;i1) { // cpgmove(s.x0,s.y0); // cpgdraw(s.x1,s.y1); // } if (s.state==2) { for (i=0;i<5;i++) { if (i==0 || i==4) { dx=-s.w; dy=-s.w; } else if (i==1) { dx=-s.w; dy=s.w; } else if (i==2) { dx=s.w; dy=s.w; } else if (i==3) { dx=s.w; dy=-s.w; } dx=0.0; if (i<2 || i==4) { x=s.ca*dx-s.sa*dy+s.x0; y=s.sa*dx+s.ca*dy+s.y0; } else { x=s.ca*dx-s.sa*dy+s.x1; y=s.sa*dx+s.ca*dy+s.y1; } if (i==0) cpgmove(x,y); else cpgdraw(x,y); } } cpgsci(1); return; } void apply_mask(struct image *img,struct selection s) { int i,j,k; float x,y,dx,dy; for (i=0;inaxis1;i++) { for (j=0;jnaxis2;j++) { k=i+img->naxis1*j; if (img->mask[k]==0) continue; dx=(float) i-s.x0; dy=(float) j-s.y0; x=s.ca*dx+s.sa*dy; y=-s.sa*dx+s.ca*dy; if (x>=0.0 && x<=s.r && y>-s.w && yzmax[k]>s.zmin) { img->mask[k]=1; } else { img->mask[k]=0; } } } return; } void apply_mask_sigma(struct image *img,struct selection s) { int i,j,k; float x,y,dx,dy; for (i=0;inaxis1;i++) { for (j=0;jnaxis2;j++) { k=i+img->naxis1*j; if (img->mask[k]==0) continue; dx=(float) i-s.x0; dy=(float) j-s.y0; x=s.ca*dx+s.sa*dy; y=-s.sa*dx+s.ca*dy; if (x>=0.0 && x<=s.r && y>-s.w && yzsig[k]>s.zmin) { img->mask[k]=1; } else { img->mask[k]=0; } } } return; } void mask_pixel(struct image *img,float x,float y) { int i,j,k,kmin,i0,j0,flag; float r,rmin; i0=(int) x; j0=(int) y; // Find nearest pixel for (i=0,flag=0;inaxis1;i++) { for (j=0;jnaxis2;j++) { k=i+img->naxis1*j; r=sqrt(pow(i-i0,2)+pow(j-j0,2)); if (img->mask[k]==0) continue; if (flag==0 || rmask[kmin]=0; return; } void fit(struct observation *obs,struct image img) { int i,j,k,l,n; float *t,*dt,*x,*y; float tmin,tmax,tmid; float chi2x,chi2y,ax[2],sax[2],ay[2],say[2]; // Count number of points for (i=0,n=0;itmax) tmax=t[i]; } } tmid=0.5*(tmin+tmax); printf("Using points between %.3f and %.3f\n",tmin,tmax); // Shift in time for (i=0;ix[0]=ax[0]; obs->y[0]=ay[0]; obs->x[1]=ax[0]+ax[1]*(tmin-tmid); obs->y[1]=ay[0]+ay[1]*(tmin-tmid); obs->x[2]=ax[0]+ax[1]*(tmax-tmid); obs->y[2]=ay[0]+ay[1]*(tmax-tmid); obs->state=1; obs->tmin=tmin; obs->tmax=tmax; for (i=0;i<2;i++) { obs->ax[i]=ax[i]; obs->ay[i]=ay[i]; } // Reduce point reduce_point(obs,img,tmid,ax[0],ay[0]); // Free free(t); free(dt); free(x); free(y); return; } void format_iod_line(struct observation *obs) { int mt,xt,mp,xp; char string[10]; // Time format sprintf(string,"%7.1e",obs->terr); mt=string[0]-'0'; xt=atoi(string+4)+8; // Position format if (obs->type==2) { sprintf(string,"%7.1e",obs->perr); mp=string[0]-'0'; xp=atoi(string+4)+8; } else { printf("Position format not implemented!\n"); } sprintf(obs->iod_line,"%05d %c%c %-6s %04d %c %-17s %d%d %d%d %-14s %d%d %c", obs->satno, obs->desig[0],obs->desig[1], obs->desig+2, obs->cospar, obs->conditions, obs->nfd, mt,xt, obs->type,obs->epoch, obs->pos, mp,xp, obs->behavior); return; } void find_designation(int satno0,char *desig0) { FILE *file; int satno; char desig[16]; char *env,filename[128]; // Environment variables 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)) { fscanf(file,"%d %s",&satno,desig); if (satno==satno0) { strcpy(desig0,desig); break; } } fclose(file); return; } void write_observation(struct observation obs) { FILE *file; float w,pa,dt; file=fopen("observations.txt","a"); fprintf(file,"%s\n",obs.iod_line); fclose(file); printf("Observation written\n"); dt=obs.tmax-obs.tmin; w=sqrt(obs.ax[1]*obs.ax[1]+obs.ay[1]*obs.ay[1])/dt; pa=atan2(obs.ay[1],obs.ax[1])*R2D; return; } void track(char *fileroot,struct observation obs,struct image *img,float frac) { FILE *file; char line[LIM],filename[LIM]; int flag=0,satno; float x0,y0,x1,y1,texp; int i,j,k,l,k0; int di,dj; float *z; int *wt; float dxdn,dydn,dx,dy; sprintf(filename,"%s.id",fileroot); // Open ID file file=fopen(filename,"r"); if (file==NULL) { fprintf(stderr,"ID file %s not found\n",filename); return; } while (fgetline(file,line,LIM)>0) { sscanf(line,"%s %f %f %f %f %f %d",filename,&x0,&y0,&x1,&y1,&texp,&satno); trk.x0=x0; trk.y0=y0; trk.x1=x1; trk.y1=y1; trk.satno=satno; trk.texp=texp; if (satno==obs.satno) break; } fclose(file); if (satno!=obs.satno) { fprintf(stderr,"Object %d not found\n",obs.satno); return; } dxdn=(x1-x0)/(float) img->nframes; dydn=(y1-y0)/(float) img->nframes; // Allocate z=(float *) malloc(sizeof(float)*img->naxis1*img->naxis2); wt=(int *) malloc(sizeof(int)*img->naxis1*img->naxis2); // Set to zero for (i=0;inaxis1*img->naxis2;i++) { z[i]=0.0; wt[i]=0; } // Loop over frames for (l=0;lnframes;l++) { // Offset dx=dxdn*(l-frac*img->nframes); dy=dydn*(l-frac*img->nframes); // Integer offset di=(int) floor(dx+0.5); dj=(int) floor(dy+0.5); // Set for (i=0;inaxis1;i++) { for (j=0;jnaxis2;j++) { k=i+img->naxis1*j; k0=i+di+img->naxis1*(j+dj); if (i+di>0 && i+dinaxis1 && j+dj>0 && j+djnaxis2) { wt[k]+=1; if (img->znum[k0]==l) z[k]+=img->zmax[k0]; // else // z[k]+=img->zavg[k0]; } } } } // Scale for (i=0;inaxis1*img->naxis2;i++) { if (wt[i]>0) img->zd[i]=z[i]/(float) wt[i]; else img->zd[i]=z[i]; } img->naxis3=5; free(z); free(wt); return; } int autotrack(char *fileroot,struct observation obs,struct image *img,int cflag) { FILE *file; char line[LIM],filename[LIM]; int flag=0,satno,satno0=0,i=0,n; float x0,y0,x1,y1,texp; int status=0; sprintf(filename,"%s.id",fileroot); // Open ID file file=fopen(filename,"r"); if (file==NULL) { fprintf(stderr,"ID file %s not found\n",filename); return -1; } while (fgetline(file,line,LIM)>0) { if (cflag==1 && strstr(line,"classfd")==NULL) continue; sscanf(line,"%s %f %f %f %f %f %d",filename,&trk.x0,&trk.y0,&trk.x1,&trk.y1,&trk.texp,&trk.satno); if (i==iobject) { status=1; break; } i++; } fclose(file); iobject++; return status; } int main(int argc,char *argv[]) { int i,j,k,l; int iconditions=0,ibehavior=0; struct image img; 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,frac=0.5; char c; float xmin,xmax,ymin,ymax,zmin,zmax,*z; float width; int redraw=1,layer=2,status; float lcut=4,hcut=6; struct selection s; struct observation obs; char conditions[]="EGFPBT",behavior[]="EFIRSX"; char text[128]; double doy,mjd; int year; char *env; float sigma,xa,ya; FILE *file; char filename[128]; env=getenv("ST_COSPAR"); // Default observation obs.satno=99999; strcpy(obs.desig,"99999U"); obs.cospar=atoi(env); obs.conditions='G'; strcpy(obs.nfd,"YYYYMMDDHHMMSSsss"); obs.terr=0.1; strcpy(obs.pos,"HHMMmmm+DDMMmm"); strcpy(obs.iod_line,""); obs.perr=0.3; obs.epoch=5; obs.type=2; obs.behavior='S'; obs.state=0; // Set track trk.satno=0; // Read image img=read_fits(argv[1]); // Allocate z=(float *) malloc(sizeof(float)*img.naxis1*img.naxis2); // Get fake designation mjd=nfd2mjd(img.nfd); doy=mjd2doy(mjd,&year); sprintf(obs.desig,"%02d%03.0lfA",year-2000,doy+500); cpgopen("/xs"); cpgpap(0.,1.0); //cpgpap(7,0.75); cpgask(0); cpgsch(0.8); // Default limits xmin=0.0; xmax=(float) img.naxis1; ymin=0.0; ymax=(float) img.naxis2; width=img.naxis1; // Default selection s.state=0; s.w=10; s.zmin=5.0; s.zmax=20.0; s.fit=0; // Set cospas obs.cospar=img.cospar; for (;;) { if (redraw==1) { cpgeras(); cpgsvp(0.1,0.95,0.1,0.95); cpgwnad(xmin,xmax,ymin,ymax); cpglab("x (pix)","y (pix)"," "); cpgsfs(2); cpgctab (heat_l,heat_r,heat_g,heat_b,5,1.0,0.5); 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); // Apply mask for (i=0;i5.0) { reduce_point(&obs,img,frac*img.exptime,x,y); obs.x[0]=x; obs.y[0]=y; obs.state=2; } redraw=1; layer=4; } continue; } // Find peak if (c=='p') { sigma=find_peak(img.zd,img.naxis1,img.naxis2,(int) xmin,(int) xmax,(int) ymin,(int) ymax,2.0,11,11,&x,&y); printf("%f %f %f\n",x,y,sigma); reduce_point(&obs,img,frac*img.exptime,x,y); obs.x[0]=x; obs.y[0]=y; obs.state=2; redraw=1; continue; } // Track if (c=='t') { printf("Provide satellite ID: "); scanf("%d",&obs.satno); find_designation(obs.satno,obs.desig); track(argv[1],obs,&img,frac); layer=4; redraw=1; } if (c=='\t') { status=autotrack(argv[1],obs,&img,1); if (status==1) { obs.satno=trk.satno; find_designation(obs.satno,obs.desig); track(argv[1],obs,&img,frac); redraw=1; layer=4; } } // Write obs if (c=='w') { write_observation(obs); continue; } // Reduce if (c=='m') { reduce_point(&obs,img,-1.0,x,y); obs.x[0]=x; obs.y[0]=y; obs.state=2; redraw=1; continue; } // Change fraction if (c=='e') { if (frac>0.49 && frac<0.51) frac=1.0; else if (frac>0.51) frac=0.0; else if (frac<0.49) frac=0.5; printf("Fraction: %.1f\n",frac); iobject=0; } // Change fraction if (c=='E') { frac+=0.1; if (frac>1.0) frac=0.0; printf("Fraction: %.1f\n",frac); iobject=0; } // Reduce if (c=='M' || c=='D') { reduce_point(&obs,img,frac*img.exptime,x,y); obs.x[0]=x; obs.y[0]=y; obs.state=2; redraw=1; continue; } // Get designation if (c=='d') { printf("Provide satellite number: "); scanf("%d",&obs.satno); find_designation(obs.satno,obs.desig); redraw=1; continue; } // Toggle condition if (c=='C') { iconditions++; if (iconditions>strlen(conditions)-1) iconditions=0; obs.conditions=conditions[iconditions]; redraw=1; continue; } // Toggle behavior if (c=='B') { ibehavior++; if (ibehavior>strlen(behavior)-1) ibehavior=0; obs.behavior=behavior[ibehavior]; redraw=1; continue; } // Reread if (c=='R') { img=read_fits(argv[1]); redraw=1; continue; } // Start if (c=='s' && s.state==0) { s.x0=x; s.y0=y; s.state=1; redraw=1; continue; } // Fit if (c=='F') { fit(&obs,img); redraw=1; continue; } // End if (c=='f' && s.state==1) { s.x1=x; s.y1=y; s.a=atan2(s.y1-s.y0,s.x1-s.x0); s.ca=cos(s.a); s.sa=sin(s.a); s.r=sqrt(pow(s.x0-s.x1,2)+pow(s.y0-s.y1,2)); s.state=2; apply_mask_sigma(&img,s); //s.zmin=zmin; redraw=1; continue; } // Mask pixel if (c=='X' && s.state!=0) { mask_pixel(&img,x,y); apply_mask(&img,s); redraw=1; continue; } // Change level if (c=='+' || c=='=') { s.zmin*=1.01; printf("%.4f\n",s.zmin); apply_mask_sigma(&img,s); redraw=1; continue; } if (c=='-') { s.zmin/=1.01; printf("%.4f\n",s.zmin); apply_mask_sigma(&img,s); redraw=1; continue; } // Mean if (isdigit(c)) { layer=c-'0'-1; redraw=1; continue; } // Adjust cuts if (c=='v') { lcut*=2; hcut*=2; redraw=1; continue; } if (c=='b') { lcut/=2; hcut/=2; if (lcut<0.5) lcut=0.5; if (hcut<0.75) hcut=0.75; redraw=1; continue; } // Center if (c=='c') { xmin=x-0.5*width; xmax=x+0.5*width; ymin=y-0.5*width*img.naxis2/img.naxis1; ymax=y+0.5*width*img.naxis2/img.naxis1; redraw=1; continue; } // Zoom if (c=='z') { width/=2; xmin=x-0.5*width; xmax=x+0.5*width; ymin=y-0.5*width*img.naxis2/img.naxis1; ymax=y+0.5*width*img.naxis2/img.naxis1; redraw=1; continue; } // Unzoom if (c=='x') { width*=2; xmin=x-0.5*width; xmax=x+0.5*width; ymin=y-0.5*width*img.naxis2/img.naxis1; ymax=y+0.5*width*img.naxis2/img.naxis1; redraw=1; continue; } // Reset if (c=='r') { xmin=0.0; xmax=(float) img.naxis1; ymin=0.0; ymax=(float) img.naxis2; width=img.naxis1; lcut=4.0; hcut=6.0; s.state=0; s.fit=0; obs.state=0; redraw=1; continue; } if (c=='h'){ printf("Reduce Satellite tracks. "); printf("q Quit\n"); printf("TAB track and stack objects automatically (only classfd sats)\n"); printf("w write IOD observation to observations.txt\n"); printf("M/D measure stack and track position (also middle mouse button)\n"); printf("e change fraction (0.0 to start, 0.5 for medium, 1.0 for the end)\n"); printf("d provide NORAD satellite number\n"); printf("C toggle IOD observing conditions G-Good F-Fair P-Poor B-Bad T-Terrible E-Excellent\n"); printf("B toggle behavior of sat.: F-Flash I-Irregular R-Regular S-Steady X-Uspecified E-Extremely weak\n"); printf("s select start of satellite track\n"); printf("f select end of satellite track\n"); printf("F fit satellite track\n"); printf("+/= Increase level of masking pixels\n"); printf("- Lower level for masking pixels (This does not seem to work)\n"); printf("1 go to the mean pixel value FITS layer\n"); printf("2 go to the FITS standard deviation layer\n"); printf("3 go to the maximum pixel value FITS layer\n"); printf("4 go to the frame number of the maximum pixel value FITS layer\n"); printf("5 go to the stack and track layer (only after 't' or 'TAB')\n"); printf("v lower dynamic range\n"); printf("b increase dynamic range\n"); printf("c center on cursor\n"); printf("z zoom in at cursor\n"); printf("x zoom out at cursor\n"); printf("R/r reset to start\n"); printf("m measure position of pixel\n"); printf("t track & stack, give NORAD satellite number\n"); printf("E change fraction in tenths\n"); printf("X pixel mask (also with mouse scroll wheel)\n"); } } cpgend(); free(img.zavg); free(img.zstd); free(img.zmax); free(img.znum); free(img.zd); free(img.zsig); 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")); img.nframes=atoi(qfits_query_hdr(filename,"NFRAMES")); // 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")); // Timestamps img.dt=(float *) malloc(sizeof(float)*img.nframes); for (i=0;i2) 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; fsec=floor(1000.0*(sec-floor(sec))); sprintf(date,"%04d%02d%02d%02d%02d%02.0f%03.0f",(int) year,(int) month,(int) day,(int) hour,(int) min,floor(sec),fsec); return; } // Convert Decimal into Sexagesimal void dec2s(double x,char *s,int type) { int i; double sec,deg,min,fmin; char sign; sign=(x<0 ? '-' : '+'); x=60.*fabs(x); min=fmod(x,60.); x=(x-min)/60.; // deg=fmod(x,60.); deg=x; if (type==0) fmin=floor(1000.0*(min-floor(min))); else fmin=floor(100.0*(min-floor(min))); if (type==0) sprintf(s,"%02.0f%02.0f%03.0f",deg,floor(min),fmin); else sprintf(s,"%c%02.0f%02.0f%02.0f",sign,deg,floor(min),fmin); return; } // Linear least squares fit float linear_fit(float x[],float y[],int n,float a[],float sa[]) { int i; float sum,sumx,sumy,sumxx,sumxy; float w,d,chi2,covar,r; // Compute sums sum=sumx=sumy=sumxx=sumxy=0.; for (i=0;i 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; } // 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; }