1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
|
/**************************************************************************
* Johns Hopkins University
* Center for Astrophysical Sciences
* FUSE
*************************************************************************
*
* synopsis: cf_jitter_diag input_file raw_file output_file
*
* Description: Reads a FITS file containing housekeeping data and
* generates a FITS file containing the jitter information
* for the observation. This program is used to generate
* diagnostics of the jitter performance during an observation
*
* Arguments: input_file Input raw FITS housekeeping file for an observation
* The header of this is used as a template
* for the output file
* raw_file Raw data file - used to get the start time and the
* exposure time
* output_file FITS table containing the jitter information
*
*
*Contents of output file:
* 1. Time of sample (in seconds from start)
* 2. shifts dx and dy (in arcsec) of the pointing from a reference position
* 3. tracking quality flag (best=5, worst=0)
*
*
* HISTORY: 01/22/02 v1.0 Robinson Begin work
* 08/14/02 v1.1 Robinson populate JIT_STATUS keyword
* 09/20/02 v1.11 Robinson - update FILENAME, FILETYPE keywords
* - change EXP_DUR keyword to reflect
* total time duration of jitter data
* 11/04/02 v1.2 Robinson change method in which gaps are filled
* we no longer assume that the data is
* tabulated at regular intervals. Also
* checks that tabulated times start BEFORE
* the observation start time
* 12/17/02 v1.3 Robinson Slight change in definitions of TRAKFLG
* values.
* 01/17/03 v1.4 Robinson slight change in calculating summary of
* jitter properties
* 05/22/03 v1.5 rdr changed initialization of arrays
* 06/10/03 v1.6 rdr Correct problem in determining ref
* quaternian
* 06/23/03 v1.7 rdr Adjust calculation on some of the
* keywords
* 06/25/03 v1.8 rdr Added call to raw data file to determine
* actual start and exposure times
* 06/27/03 v1.9 rdr Corrected procedure for determining
* reference quaternian
* 03/03/04 v1.10 bjg include unistd.h
* 06/24/05 v1.11 wvd Delete unused variables.
* 08/24/07 v1.12 bot changed TINT to TLONG for time l.826.
*
**************************************************************************/
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "calfuse.h"
static char CF_PRGM_ID[] = "cf_jitter_diag";
static char CF_VER_NUM[] = "1.12";
int quatprod(double *, double *, double *) ;
int main(int argc, char *argv[])
{
FILE *output, *ftest ;
fitsfile *infits, *outfits ;
int hdutype, tfields, dstatus ;
int nvalid, nvalid5, optc, rtime ;
int aattmode_colnum, pflg=0 ;
int *aattflg, tflg, qvalidt ;
int tcolnum, fpdquat1_colnum, fpdquat2_colnum, fpdquat3_colnum ;
int aquat1_colnum, aquat2_colnum, aquat3_colnum, slew_colnum ;
int status, tcol;
int dxcol, dycol, trkcol, anynull, intnull=0 ;
int fpdexp_colnum, qvalid_colnum, cents1_colnum, cents2_colnum, cents3_colnum ;
int cents4_colnum, cents5_colnum, cents6_colnum, acsflg_colnum ;
int acscmd1_colnum, acscmd2_colnum, acscmd3_colnum, sfknwn_colnum ;
int frow, felem, slewflg, ngs_used, jitlgx, jitlgy ;
int *cents1, *cents2, *cents3, *cents4, *cents5, *cents6 , *qvalid ;
int *sfknwn, *slew ;
int cents1t=0, cents2t=0, cents3t=0, cents4t=0, cents5t=0, cents6t=0 ;
int sfknwnt=0 , slewt=0, slewtime=0 ;
long i, j, numq4, numq5, numq3, numq2, numqa, numq0 ;
long npts, tval ;
long *time, qtime=0;
float tfine, tcoarse, tnull, knowntrk, unknowntrk, fjitlgx, fjitlgy ;
float targtrk ;
float ngs1, ngs2, ngs3, ngs4, ngs5, ngs6, gs_used, expdur, exptime ;
float dxrms, dyrms, dxave, dyave, dxrms5, dyrms5 ;
float *fpdexp, *acsflg ;
float *dx , *dy ;
double *fq1, *fq2,*fq3, *dq1, *dq2, *dq3, *mjd ;
double *acscmd1, *acscmd2, *acscmd3, fq1t, fq2t, fq3t ;
double tstrt ;
double tquat[4], dquat[4], quat_ref[4] ;
double *aq1, *aq2, *aq3, aq1t, aq2t, aq3t ;
short *trakflg ;
char buffer[FLEN_CARD];
char *ttype[] = { "TIME", "DX", "DY", "TRKFLG" } ;
char *tform[] = { "1J", "1E", "1E", "1I" } ;
char *tunit[] = { "seconds", "arcsec", "arcsec", " "} ;
char textname[7]="jitter" ;
char opts[] = "hv:";
char usage[] =
"Usage:\n"
" cf_jitr_diag [-h] [-v level] hskpfile rawfile outfile\n";
char option[] =
"Options:\n"
" -h: this help message\n"
" -v: verbosity level (=1; 0 is silent)\n";
verbose_level = 1;
while ((optc = getopt(argc, argv, opts)) != -1) {
switch(optc) {
case 'h':
printf("%s\n%s", usage, option);
return 0;
case 'v':
verbose_level = atoi(optarg);
break;
}
}
cf_error_init(CF_PRGM_ID, CF_VER_NUM, stderr);
if (argc != optind+3) {
printf("%s", usage);
cf_if_error("Incorrect number of arguments");
}
cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Begin execution");
/* initialize necessary variables */
hdutype=0 ;
status=0 ;
frow=1 ;
felem=1 ;
anynull=0 ;
/* check that the housekeeping and raw data files are available */
cf_verbose(3,"checking for housekeeping file : %s ",argv[optind]) ;
ftest=fopen(argv[optind],"r") ;
if (ftest == NULL) {
cf_verbose(1,"No input housekeeping file available - returning ") ;
return 0; }
fclose( ftest ) ;
ftest=fopen(argv[optind+1],"r") ;
if (ftest == NULL) {
cf_verbose(1,"No input raw data file available - returning ") ;
return 0; }
fclose( ftest ) ;
/* Open the input raw data FITS file and read the start and exposure times */
cf_verbose(3,"opening the file %s for input ",argv[optind+1]);
FITS_open_file(&infits, argv[optind+1], READONLY, &status);
/* read the starting time and duration from the FITS header */
FITS_read_key(infits, TDOUBLE, "EXPSTART", &tstrt, buffer, &status) ;
cf_verbose(3,"start time (MJD) = %15.9f ",tstrt) ;
FITS_read_key(infits, TFLOAT, "EXPTIME", &exptime, buffer, &status) ;
exptime=(int) exptime ;
cf_verbose(3,"exposure duration (sec) = %f ",exptime) ;
/* close the raw data file and open the housekeeping file */
FITS_close_file(infits, &status) ;
FITS_open_file(&infits, argv[optind], READONLY, &status);
/* check for the existance of the output file */
output = fopen(argv[optind+2], "r") ;
if (output != NULL) {
cf_verbose(1,"output file already exists - returning ") ;
return 1 ; }
else fclose(output) ;
/* Create the output file */
FITS_create_file(&outfits, argv[optind+2], &status);
/* Copy the header and empty primary image of the input file to
the output */
FITS_copy_hdu(infits, outfits, 0, &status) ;
/* populate the STATUS keyword with 1 -
will reset keyword if everyhing goes well */
dstatus = 1 ;
FITS_update_key(outfits, TINT, "JIT_STAT", &dstatus,
"problems with jitter data", &status) ;
/* update FILENAME, FILETYPE, EXPTIME and EXPSTART keywords */
FITS_update_key(outfits, TSTRING, "FILENAME",argv[optind+2], NULL, &status) ;
FITS_update_key(outfits, TSTRING, "FILETYPE","JITTER", NULL, &status) ;
FITS_update_key(outfits, TFLOAT, "EXPTIME",&exptime, NULL, &status) ;
FITS_update_key(outfits, TDOUBLE, "EXPSTART",&tstrt, NULL, &status) ;
/* move to the first extension, which contains the table */
FITS_movabs_hdu(infits, 2, &hdutype, &status) ;
/* determine the number of times which have been tabulated */
FITS_read_key(infits, TLONG, "NAXIS2", &npts, NULL, &status) ;
cf_verbose(3,"number of samples in the table = %d ",npts) ;
/* set up arrays to contain the data to be read from the table */
mjd = (double *) cf_calloc(npts, sizeof(double)) ;
fpdexp = (float *) cf_calloc(npts, sizeof(float) ) ;
qvalid = (int *) cf_calloc(npts, sizeof(int)) ;
fq1 = (double *) cf_calloc(npts, sizeof(double) ) ;
fq2 = (double *) cf_calloc(npts, sizeof(double) ) ;
fq3 = (double *) cf_calloc(npts, sizeof(double) ) ;
aq1 = (double *) cf_calloc(npts, sizeof(double) ) ;
aq2 = (double *) cf_calloc(npts, sizeof(double) ) ;
aq3 = (double *) cf_calloc(npts, sizeof(double)) ;
aattflg = (int *) cf_calloc(npts, sizeof(int)) ;
acsflg = (float *) cf_calloc(npts, sizeof(float)) ;
acscmd1 = (double *) cf_calloc(npts, sizeof(double)) ;
acscmd2 = (double *) cf_calloc(npts, sizeof(double) ) ;
acscmd3 = (double *) cf_calloc(npts, sizeof(double) ) ;
cents1 = (int *) cf_calloc(npts, sizeof(int)) ;
cents2 = (int *) cf_calloc(npts, sizeof(int) ) ;
cents3 = (int *) cf_calloc(npts, sizeof(int) ) ;
cents4 = (int *) cf_calloc(npts, sizeof(int) ) ;
cents5 = (int *) cf_calloc(npts, sizeof(int) ) ;
cents6 = (int *) cf_calloc(npts, sizeof(int) ) ;
sfknwn = (int *) cf_calloc(npts, sizeof(int) ) ;
slew = (int *) cf_calloc(npts, sizeof(int) ) ;
/* read the data */
FITS_get_colnum(infits, CASEINSEN, "MJD", &tcolnum, &status) ;
cf_verbose(5,"column number for time = %d ",tcolnum) ;
FITS_read_col(infits, TDOUBLE, tcolnum, frow, felem, npts, &intnull,
mjd, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_EXP_DURATION", &fpdexp_colnum,
&status) ;
/*printf("column number for fdpexp = %d \n",fpdexp_colnum) ;*/
FITS_read_col(infits, TFLOAT, fpdexp_colnum, frow, felem, npts, &intnull,
fpdexp, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_MEAS_Q_VALID", &qvalid_colnum,
&status) ;
/*printf("column number for qvalid = %d \n",qvalid_colnum) ;*/
FITS_read_col(infits, TINT, qvalid_colnum, frow, felem, npts, &intnull,
qvalid, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_Q_ECI2BDY_1", &fpdquat1_colnum,
&status) ;
/*printf("column number for fq1 = %d \n",fpdquat1_colnum) ;*/
FITS_read_col(infits, TDOUBLE, fpdquat1_colnum , frow, felem, npts, &intnull,
fq1, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_Q_ECI2BDY_2", &fpdquat2_colnum,
&status) ;
/*printf("column number for fq2 = %d \n",fpdquat2_colnum) ;*/
FITS_read_col(infits, TDOUBLE, fpdquat2_colnum , frow, felem, npts, &intnull,
fq2, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_Q_ECI2BDY_3", &fpdquat3_colnum,
&status) ;
/*printf("column number for fq3 = %d \n",fpdquat3_colnum) ;*/
FITS_read_col(infits, TDOUBLE, fpdquat3_colnum , frow, felem, npts, &intnull,
fq3, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AATTQECI2BDY_1", &aquat1_colnum, &status) ;
/*printf("column number for aq1 = %d \n",aquat1_colnum) ;*/
FITS_read_col(infits, TDOUBLE, aquat1_colnum , frow, felem, npts, &intnull,
aq1, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AATTQECI2BDY_2", &aquat2_colnum, &status) ;
/*printf("column number for aq2 = %d \n",aquat2_colnum) ;*/
FITS_read_col(infits, TDOUBLE, aquat2_colnum, frow, felem, npts, &intnull,
aq2, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AATTQECI2BDY_3", &aquat3_colnum, &status) ;
/*printf("column number for aq3 = %d \n",aquat3_colnum) ;*/
FITS_read_col(infits, TDOUBLE, aquat3_colnum, frow, felem, npts, &intnull,
aq3, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AATTMODE", &aattmode_colnum, &status) ;
/*printf("column number for aattmode = %d \n",aattmode_colnum) ;*/
FITS_read_col(infits, TINT, aattmode_colnum, frow, felem, npts, &intnull,
aattflg, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_AT_CMD_ATT", &acsflg_colnum, &status) ;
/*printf("column number for acsflg = %d \n",acsflg_colnum) ;*/
FITS_read_col(infits, TFLOAT, acsflg_colnum, frow, felem, npts, &intnull,
acsflg, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AQECI2BDYCMD_1", &acscmd1_colnum, &status) ;
/*printf("column number for acscmd1 = %d \n",acscmd1_colnum) ;*/
FITS_read_col(infits, TDOUBLE, acscmd1_colnum, frow, felem, npts, &intnull,
acscmd1, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AQECI2BDYCMD_2", &acscmd2_colnum, &status) ;
/*printf("column number for acscmd2 = %d \n",acscmd2_colnum) ;*/
FITS_read_col(infits, TDOUBLE, acscmd2_colnum, frow, felem, npts, &intnull,
acscmd2, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "AQECI2BDYCMD_3", &acscmd3_colnum, &status) ;
/* printf("column number for acscmd3 = %d \n",acscmd3_colnum) ;*/
FITS_read_col(infits, TDOUBLE, acscmd3_colnum, frow, felem, npts, &intnull,
acscmd3, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "CENTROID1_STATUS", ¢s1_colnum,
&status) ;
/* printf("column number for guide star 1 status = %d \n",cents1_colnum) ; */
FITS_read_col(infits, TINT, cents1_colnum, frow, felem, npts, &intnull,
cents1, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "CENTROID2_STATUS", ¢s2_colnum,
&status) ;
/* printf("column number for guide star 2 status = %d \n",cents2_colnum) ; */
FITS_read_col(infits, TINT, cents2_colnum, frow, felem, npts, &intnull,
cents2, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "CENTROID3_STATUS", ¢s3_colnum,
&status) ;
/* printf("column number for guide star 3 status = %d \n",cents3_colnum) ; */
FITS_read_col(infits, TINT, cents3_colnum, frow, felem, npts, &intnull,
cents3, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "CENTROID4_STATUS", ¢s4_colnum,
&status) ;
/* printf("column number for guide star 4 status = %d \n",cents4_colnum) ; */
FITS_read_col(infits, TINT, cents4_colnum, frow, felem, npts, &intnull,
cents4, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "CENTROID5_STATUS", ¢s5_colnum,
&status) ;
/* printf("column number for guide star 5 status = %d \n",cents5_colnum) ; */
FITS_read_col(infits, TINT, cents5_colnum, frow, felem, npts, &intnull,
cents5, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "CENTROID6_STATUS", ¢s6_colnum,
&status) ;
/* printf("column number for guide star 6 status = %d \n",cents6_colnum) ; */
FITS_read_col(infits, TINT, cents6_colnum, frow, felem, npts, &intnull,
cents6, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_STARFLD_KNWN", &sfknwn_colnum,
&status) ;
/* printf("column number for starfield known status = %d \n",sfknwn_colnum) ; */
FITS_read_col(infits, TINT, sfknwn_colnum, frow, felem, npts, &intnull,
sfknwn, &anynull, &status) ;
FITS_get_colnum(infits, CASEINSEN, "I_FPD_NEW_CMD_Q", &slew_colnum,
&status) ;
/* printf("column number for slew status = %d \n",slew_colnum) ; */
FITS_read_col(infits, TINT, slew_colnum, frow, felem, npts, &intnull,
slew, &anynull, &status) ;
/* close the input file */
FITS_close_file(infits, &status) ;
/* check for problems with the tabulated start time */
if (fabs(mjd[0]-tstrt) > 1) {
cf_verbose(1,"Problems with tabulated start time ") ;
cf_verbose(1," Value of tabulated start time = %15.7f ",tstrt) ;
cf_verbose(1," First tabulated MJD = %15.7f ",mjd[0]) ;
/* update JIT_STAT keyword */
dstatus = 1 ;
FITS_update_key(outfits, TINT, "JIT_STAT", &dstatus,
"problems with tab start time", &status) ;
FITS_close_file(outfits, &status) ;
return 1; }
/* make sure that the tabulates times start BEFORE the start of the observation,
Otherwise there may be missing data or an error in the tabulated start time */
tval=(long) (0.5 + (mjd[0]-tstrt) * 86400.) ;
if (tval > 0) {
cf_verbose(1,"WARNING: There may be missing data or an error in the start time \n") ;
cf_verbose(1," The first tabulated time is %d seconds from obs start ", tval) ;
/* update JIT_STAT keyword */
dstatus = 1 ;
FITS_update_key(outfits, TINT, "JIT_STAT", &dstatus,
"problems with tab start time", &status) ;
FITS_close_file(outfits, &status) ;
return 1 ;
}
/* fill in the gaps in the data set
- ACS quaternians are generally tabulated every other second
- FPD quaternians can be every second or every other second
- AATTMODE flags tabulates every 5 seconds
- ACS flags (acsflg) - tabulated every 16 seconds
NOTE: there can be irregularities in the spacing. Thus, save the last
tabulated value and use this in filling in missing data for a given time */
/* ACS quaternians */
aq1t = 0. ;
aq2t = 0. ;
aq3t = 0. ;
for (i=0 ; i<npts ; i++) {
if ( aq1[i] > -1 && aq2[i] > -1){
aq1t=aq1[i] ;
aq2t=aq2[i] ;
aq3t=aq3[i] ; }
else {
aq1[i] = aq1t ;
aq2[i] = aq2t ;
aq3[i] = aq3t ; }
}
/* FPD quaternians and qvalid flags
only update the one following a good quaternian. if there is another one
with no quaternian after that, do not update it */
fq1t = 0. ;
fq2t = 0. ;
fq3t = 0. ;
qvalidt = 0 ;
tflg = -1 ;
for (i=0 ; i<npts ; i++) {
if ( (fabs(fq1[i]) > 0.) && (fabs(fq2[i]) > 0.) ){
fq1t=fq1[i] ;
fq2t=fq2[i] ;
fq3t=fq3[i] ;
qvalidt = qvalid[i] ;
cents1t = cents1[i] ;
cents2t = cents2[i] ;
cents3t = cents3[i] ;
cents4t = cents4[i] ;
cents5t = cents5[i] ;
cents6t = cents6[i] ;
sfknwnt = sfknwn[i] ;
slewt = slew[i] ;
tflg = 1 ; }
else if (tflg > 0) {
fq1[i] = fq1t ;
fq2[i] = fq2t ;
fq3[i] = fq3t ;
qvalid[i] = qvalidt ;
cents1[i] = cents1t ;
cents2[i] = cents2t ;
cents3[i] = cents3t ;
cents4[i] = cents4t ;
cents5[i] = cents5t ;
cents6[i] = cents6t ;
sfknwn[i] = sfknwnt ;
slew[i] = slewt ;
tflg = -1 ; }
}
/* AATTMODE flag - update as long as quaternians are
present */
tflg = -1 ;
for (i=0 ; i<npts-1 ; i++) {
if (aattflg[i] > -1) tflg = aattflg[i] ;
else {
aattflg[i] = -10 ;
if (aq1[i] > -1) aattflg[i]=3 ;
if ((fabs(fq1[i]) > 0.) && ( fabs(fq2[i]) > 0. ) ) aattflg[i]=tflg ; }
}
/* ACSFLG flag */
tflg = -10 ;
for (i=0 ; i<npts-1 ; i++) {
if (acsflg[i] > -1) tflg = acsflg[i] ;
else acsflg[i] = tflg ;
}
/********** derive the final quats arrays and the tracking flags *******/
/* set up arrays to contain the data */
time = (long *) cf_calloc(npts, sizeof(long) ) ;
trakflg = (short *) cf_calloc(npts, sizeof(short) ) ;
dq1 = (double *) cf_calloc(npts, sizeof(double) ) ;
dq2 = (double *) cf_calloc(npts, sizeof(double)) ;
dq3 = (double *) cf_calloc(npts, sizeof(double) ) ;
dx = (float *) cf_calloc(npts, sizeof(float) ) ;
dy = (float *) cf_calloc(npts, sizeof(float) ) ;
/* fill in the time array with times (in seconds) from the start of the observation */
for (i=0 ; i<npts ; i++) {
tval=(long) (0.5 + (mjd[i]-tstrt) * 86400.) ;
time[i] = tval ; }
/* determine the reference quat by looking at the commanded ACS quaternian (in arrays
acscmd1, acscmd2 and acscmd3) when they have converged to the fpd commanded
quaternian - i.e. when the AT_CMD_ATT flag is 1 (held in the array acsflg) -
Make sure that the time for convergence is AFTER the start of the observation and that
the starfield is known (i.e. sfknwn = 1). Also, because of the 16s sample time of
the ascflg array, require that the condition exists for at least 30 consequtive seconds
before accepting the quaternians.
qtime = time at which the quaternians were found. This is the earliest time in the exposure
for which reliable positions are available*/
rtime=0 ;
for (i=0 ; i<npts; i++) {
if (acsflg[i] == 1 && time[i] > 0 && sfknwn[i] == 1) {
rtime += 1 ;
cf_verbose(4,"quat ref cond exists at time=%d, rtime=%d ",time[i],rtime) ;
if(rtime == 1) qtime=time[i] ;
if (rtime > 30 && acscmd1[i] > -1 && acscmd2[i] > -1 && acscmd3[i] > -1 ) {
quat_ref[0]=acscmd1[i] ;
quat_ref[1]=acscmd2[i] ;
quat_ref[2]=acscmd3[i] ;
quat_ref[3]=sqrt( 1. - quat_ref[0]*quat_ref[0] - quat_ref[1]*quat_ref[1] - quat_ref[2]*quat_ref[2] ) ;
goto skip ; }
}
else rtime=0 ;
}
/* if we are here, then the flag was never set and the reference quat not determined */
cf_verbose(1," Problem determining the reference quaternians ") ;
/* determine cause of failure */
pflg = 0 ;
for (i=0 ; i<npts; i++) if (acsflg[i] == 1) pflg=1 ;
if (pflg == 0) {
cf_verbose(1," AT_CMD_ATT flag was never set ") ;
/* update JIT_STAT keyword */
dstatus = 2 ;
FITS_update_key(outfits, TINT, "JIT_STAT", &dstatus,
"AT_CMD_ATT flg never set", &status) ;
}
pflg = 0 ;
for (i=0 ; i<npts; i++) if (sfknwn[i] == 1) pflg=1 ;
if (pflg == 0) {
printf(" UNKNOWN STAR FIELD \n") ;
/* update JIT_STAT keyword */
dstatus = 3 ;
FITS_update_key(outfits, TINT, "JIT_STAT", &dstatus,
"unknown star field", &status) ;
}
FITS_close_file(outfits, &status) ;
return 1 ;
skip: ;
cf_verbose(3," ") ;
cf_verbose(3,"reference quat values - from ACS commanded pos ") ;
cf_verbose(3,"found at time %d \n",qtime) ;
for (i=0; i<4 ; i++) cf_verbose(3,"for i=%d, quat=%18.15f ",i,quat_ref[i]) ;
/* determine the value of the tracking flags and identify which quaternians to use */
for (i=0; i<npts ; i++) {
if (fq1[i] > -1 && fq2[i] > -1 && qvalid[i] > 0) {
dq1[i] = fq1[i] ;
dq2[i] = fq2[i] ;
dq3[i] = fq3[i] ;
if (sfknwn[i] == 1 && aattflg[i] == 5) trakflg[i] = (short) 5 ;
if (sfknwn[i] == 0 && aattflg[i] == 5) trakflg[i] = (short) 4 ;
if (aattflg[i] == 4) trakflg[i] = (short) 3 ; }
else if (aq1[i] > -1 && aq2[i] > -1 ) {
dq1[i] = aq1[i] ;
dq2[i] = aq2[i] ;
dq3[i] = aq3[i] ;
if(aattflg[i] == 4) trakflg[i] = (short) 2 ;
if(aattflg[i] == 3) trakflg[i] = (short) 1 ;}
else {
dq1[i] = -10. ;
dq2[i] = -10. ;
dq3[i] = -10. ;
trakflg[i]= (short) 0 ; }
}
/* determine the shift in the quaturnians and derive the changes
in x and y which they represent :
DX (from q2 values : dq2=dx/2) and DY (from q1 values : dq1=-dy/2)
in arcseconds - the conversion factor used is the number of arcsec
per radian * 2 */
for (i=0l ; i<npts ; i++) {
if (trakflg[i] > 0) {
tquat[0] = dq1[i] ;
tquat[1] = dq2[i] ;
tquat[2] = dq3[i] ;
tquat[3] = sqrt(1. - dq1[i]*dq1[i] - dq2[i]*dq2[i] - dq3[i]*dq3[i] ) ;
/* initialize dquat */
for (j=0; j<4 ; j++) dquat[j]=0. ;
/* now determine the change in quat */
quatprod(tquat, quat_ref, dquat) ;
/* convert of arcsec in x and y */
dy[i] = (float) -dquat[0] * 412541. ;
dx[i] = (float) dquat[1] * 412541. ; }
else {
dx[i] = -999. ;
dy[i] = -999. ; }
}
/****** provide keywords in the top level header which describe the observations ****/
/* determine the time span in the jitter file (in seconds) and set EXP_DUR to
this value */
expdur = (float) (time[npts-1] - time[0]) + 1. ;
FITS_update_key(outfits, TFLOAT, "EXP_DUR", &expdur,
"duration of jitter data (sec)", &status) ;
/* check for a short exposure and reset exptime if necessary */
if (time[npts-1] < exptime) {
exptime = time[npts-1] ;
cf_verbose(2,"short exposure- reset exptime to %f ",exptime) ;
}
/* determine the statistics of the guiding */
numq4=0 ;
numq5=0 ;
numq3=0 ;
numq2=0 ;
numqa=0 ;
numq0=0 ;
cf_verbose(3,"exposure duration = %f ",expdur) ;
for (i=0; i<npts ; i++) {
cf_verbose(6,"at i=%d, trakflg=%d, qvalid=%d, time=%f ",
i,trakflg[i], qvalid[i], time[i] ) ;
if(trakflg[i] == 5 && qvalid[i] > 0 && time[i] > 0 && time[i] <= exptime)
numq5+=1 ;
if(trakflg[i] == 4 && time[i] > 0 && time[i] <= exptime) numq4+=1 ;
if(trakflg[i] == 3 && time[i] > 0 && time[i] <= exptime) numq3+=1 ;
if(trakflg[i] == 2 && time[i] > 0 && time[i] <= exptime) numq2+=1 ;
if(trakflg[i] == 1 && time[i] > 0 && time[i] <= exptime) numqa+=1 ;
if(trakflg[i] == 0 && time[i] > 0 && time[i] <= exptime) numq0+=1 ; }
cf_verbose(3," ") ;
cf_verbose(3,"duration of jitter data =%f, exposure time = %f ",expdur,exptime) ;
cf_verbose(3,"number of samples in fine track with known GS = %d ",numq5) ;
cf_verbose(3,"number of samples in fine track with unknown GS = %d ",numq4) ;
cf_verbose(3,"number of samples in coarse track = %d ",numq3) ;
cf_verbose(3,"number of samples using ACS quaternians = %d ",numq2) ;
cf_verbose(3,"number of samples with no quaternians = %d ",numq0) ;
/* tfine, tcoarse and tnull are the fraction of the total exposure
when the observation is in fine track, coarse track and no track */
tfine = (float) (numq5+numq4) / exptime ;
tcoarse = (float) (numq3+numq2+numqa) / exptime ;
tnull = (float) numq0 / exptime ;
FITS_update_key(outfits, TFLOAT, "FINE_GDE", &tfine,
"fraction of exp in fine guide", &status) ;
FITS_update_key(outfits, TFLOAT, "COARSGDE", &tcoarse,
"fraction of exp in coarse guide", &status) ;
FITS_update_key(outfits, TFLOAT, "NOGDEINF", &tnull,
"fraction of exp with no guiding info", &status) ;
/* determine the properties of the guide stars */
ngs1=0. ;
ngs2=0. ;
ngs3=0. ;
ngs4=0. ;
ngs5=0. ;
ngs6=0. ;
for (i=0; i<npts ; i++) {
if (cents1[i] == 2 && time[i] > 0 && time[i] <= exptime) ngs1+=1. ;
if (cents2[i] == 2 && time[i] > 0 && time[i] <= exptime) ngs2+=1. ;
if (cents3[i] == 2 && time[i] > 0 && time[i] <= exptime) ngs3+=1. ;
if (cents4[i] == 2 && time[i] > 0 && time[i] <= exptime) ngs4+=1. ;
if (cents5[i] == 2 && time[i] > 0 && time[i] <= exptime) ngs5+=1. ;
if (cents6[i] == 2 && time[i] > 0 && time[i] <= exptime) ngs6+=1. ; }
/* convet to fraction of observing time and put into keywords */
ngs1 = ngs1 / exptime ;
FITS_update_key(outfits, TFLOAT, "GS1_USED", &ngs1,
"fraction of exp using guide star 1", &status) ;
ngs2 = ngs2 / exptime ;
FITS_update_key(outfits, TFLOAT, "GS2_USED", &ngs2,
"fraction of exp using guide star 2", &status) ;
ngs3 = ngs3 / exptime ;
FITS_update_key(outfits, TFLOAT, "GS3_USED", &ngs3,
"fraction of exp using guide star 3", &status) ;
ngs4 = ngs4 / exptime ;
FITS_update_key(outfits, TFLOAT, "GS4_USED", &ngs4,
"fraction of exp using guide star 4", &status) ;
ngs5 = ngs5 / exptime ;
FITS_update_key(outfits, TFLOAT, "GS5_USED", &ngs5,
"fraction of exp using guide star 5", &status) ;
ngs6 = ngs6 / exptime ;
FITS_update_key(outfits, TFLOAT, "GS6_USED", &ngs6,
"fraction of exp using guide star 6", &status) ;
/* determine the number of guide stars used during the observation */
ngs_used = 0 ;
if (ngs1 > 0) ngs_used += 1 ;
if (ngs2 > 0) ngs_used += 1 ;
if (ngs3 > 0) ngs_used += 1 ;
if (ngs4 > 0) ngs_used += 1 ;
if (ngs5 > 0) ngs_used += 1 ;
if (ngs6 > 0) ngs_used += 1 ;
FITS_update_key(outfits, TINT, "NGS_USED", &ngs_used,
"number of guide stars used", &status) ;
cf_verbose(3," ") ;
cf_verbose(3,"number of guide stars used = %d \n",ngs_used) ;
/* determine times of known and unknown tracking and tracking on the target*/
knowntrk = 0. ;
unknowntrk = 0. ;
targtrk = 0. ;
gs_used = 0. ;
for (i=0 ; i< npts ; i++) {
if (qvalid[i] == 1 && time[i] > 0 && time[i] <= exptime) gs_used+=1. ;
if (sfknwn[i] == 1 && qvalid[i] ==1 && time[i] > 0 && time[i] <= exptime)
knowntrk+=1. ;
if (sfknwn[i] == 0 && qvalid[i] ==1 && time[i] > 0 && time[i] <= exptime)
unknowntrk+=1. ;
if (sfknwn[i] == 1 && acsflg[i] == 1 && time[i] > 0 && time[i] <= exptime)
targtrk += 1. ;
}
/* check for digitization errors in targtrk (caused by the 16s cadence of acsflg) */
if (targtrk+16 > exptime) targtrk = exptime ;
cf_verbose(3,"seconds when guide stars are used = %f",gs_used ) ;
cf_verbose(3,"seconds tracking on known stars = %f ",knowntrk) ;
cf_verbose(3,"seconds tracking on unknown stars = %f ",unknowntrk) ;
cf_verbose(3,"seconds tracking on the target = %f ",targtrk ) ;
knowntrk = knowntrk / exptime ;
unknowntrk = unknowntrk / exptime ;
targtrk = targtrk / exptime ;
gs_used = gs_used / exptime ;
FITS_update_key(outfits, TFLOAT, "KNOWNTRK", &knowntrk,
"fraction of exp tracking on known stars", &status) ;
FITS_update_key(outfits, TFLOAT, "UNKWNTRK", &unknowntrk,
"fraction of exp tracking on unknown stars", &status) ;
FITS_update_key(outfits, TFLOAT, "TARGTRK", &targtrk,
"fraction of exp tracking on target", &status) ;
FITS_update_key(outfits, TFLOAT, "GS_INUSE", &gs_used,
"fraction of exp tracking on guide stars", &status) ;
/* determine whether a new attitude is commanded during the exposure */
slewflg = -1 ;
for (i=0; i<npts ; i++)
if(time[i] > 0 && slew[i] > 0 && time[i] <= exptime) slewflg = 1 ;
FITS_update_key(outfits, TINT, "SLEWFLG", &slewflg,
"slew commanded during obs (if > 0)", &status) ;
if (slewflg > 0) {
cf_verbose(1," ") ;
cf_verbose(1,"SLEW COMMANDED DURING OBSERVATION!!! ") ; }
/* determine the slewing time - note that there is a 16s time
resolution on the sampling of acsflg. Thus, slews of less than 16s
are not real */
slewtime=0 ;
FITS_update_key(outfits, TINT, "SLEWTIME", &slewtime,
"time spent slewing (sec)", &status) ;
for (i=0; i<npts; i++)
if (acsflg[i] < 1 && time[i] > 0 && time[i] <= exptime ) slewtime+=1 ;
if (slewtime > 16) {
FITS_update_key(outfits, TINT, "SLEWTIME", &slewtime,
"time spent slewing (sec)", &status) ;
slewflg=1 ;
FITS_update_key(outfits, TINT, "SLEWFLG", &slewflg,
"slew commanded during obs (if > 0)", &status) ;
cf_verbose(3,"SLEW OCCURRED DURING OBSERVATION!!! ") ;
cf_verbose(3,"Time (sec) spent slewing = %d \n",slewtime) ;
}
/* determine basic properties of the jitter
- these properties are only determined during the time of the exposure where the
spacecraft is guiding on the target */
dxrms = 0. ;
dxrms5 = 0. ;
dyrms = 0. ;
dyrms5 = 0. ;
dxave = 0. ;
dyave = 0. ;
nvalid = 0 ;
nvalid5 = 0 ;
for (i=0 ; i< npts ; i++)
if(sfknwn[i] == 1 && acsflg[i] == 1 && time[i] > qtime && time[i] <= exptime) {
nvalid += 1 ;
dxrms = dxrms + dx[i]*dx[i] ;
dxave = dxave + dx[i] ;
dyrms = dyrms + dy[i] * dy[i] ;
dyave = dyave + dy[i] ;
if (time[i] > exptime - 300) {
dxrms5 = dxrms5 + dx[i] * dx[i] ;
dyrms5 =dyrms5 + dy[i] * dy[i] ;
nvalid5 += 1 ; }
}
cf_verbose(3,"number of points used to determine rms jitter = %d ",nvalid) ;
if (nvalid > 0) dxrms = sqrt( dxrms / (float) nvalid) ;
if (nvalid > 0) dyrms = sqrt( dyrms / (float) nvalid) ;
if (nvalid5 > 0) dxrms5 = sqrt( dxrms5 / (float) nvalid5) ;
if (nvalid5 > 0) dyrms5 = sqrt( dyrms5 / (float) nvalid5) ;
if (nvalid > 0) dxave = dxave / (float) nvalid ;
if (nvalid > 0) dyave = dyave / (float) nvalid ;
cf_verbose(3," ") ;
cf_verbose(3,"jitter properties ") ;
cf_verbose(3,"dxave = %f, dxrms=%f, dxrms5 = %f ", dxave, dxrms, dxrms5) ;
cf_verbose(3,"dyave = %f, dyrms=%f, dyrms5 = %f ", dyave, dyrms, dyrms5) ;
FITS_update_key(outfits, TFLOAT, "POSAVG_X", &dxave,
"[arcsec] mean DX during exposure", &status) ;
FITS_update_key(outfits, TFLOAT, "POSAVG_Y", &dyave,
"[arcsec] mean DY during exposure", &status) ;
FITS_update_key(outfits, TFLOAT, "X_JITTER", &dxrms,
"[arcsec] sigma of DX during exposure", &status) ;
FITS_update_key(outfits, TFLOAT, "Y_JITTER", &dyrms,
"[arcsec] sigma of DY during exposure", &status) ;
FITS_update_key(outfits, TFLOAT, "X_JIT_5M", &dxrms5,
"[arcsec] sigma of DX during last 5 min of exp", &status) ;
FITS_update_key(outfits, TFLOAT, "Y_JIT_5M", &dyrms5,
"[arcsec] sigma of DY during last 5 min of exp", &status) ;
/* determine fraction of exposure where the dy and dx values exceed 2
sigma from the mean */
jitlgx=0 ;
jitlgy=0 ;
for (i=0 ; i<npts ; i++) {
if ( fabs(dx[i]) > 2.*dxrms) jitlgx++ ;
if ( fabs(dy[i]) > 2.*dyrms) jitlgy++ ;
}
fjitlgx= (float) jitlgx / (float) npts ;
fjitlgy = (float) jitlgy / (float) npts ;
FITS_update_key(outfits, TFLOAT, "X_JITLRG", &fjitlgx,
"frac of DX more than 2-sigma from POSAVE_X", &status) ;
FITS_update_key(outfits, TFLOAT, "Y_JITLRG", &fjitlgy,
"frac of DY more than 2-sigma from POSAVE_Y", &status) ;
/******* Generate the table and put in guiding info *****/
tfields = 4 ;
FITS_create_tbl(outfits, BINARY_TBL, 0, tfields, ttype,
tform, tunit, textname, &status) ;
fits_get_colnum(outfits, TRUE, "TIME", &tcol, &status) ;
FITS_write_col(outfits, TLONG, tcol, 1, 1, npts, time, &status) ;
fits_get_colnum(outfits, TRUE, "DX", &dxcol, &status) ;
FITS_write_col(outfits, TFLOAT, dxcol, 1, 1, npts, dx, &status) ;
fits_get_colnum(outfits, TRUE, "DY", &dycol, &status) ;
FITS_write_col(outfits, TFLOAT, dycol, 1, 1, npts, dy, &status) ;
fits_get_colnum(outfits, TRUE, "TRKFLG", &trkcol, &status) ;
FITS_write_col(outfits, TSHORT, trkcol, 1, 1, npts, trakflg, &status) ;
/**********************************************************************/
/* set the status flag as good */
FITS_movabs_hdu(outfits, 1, &hdutype, &status) ;
dstatus = 0 ;
FITS_update_key(outfits, TINT, "JIT_STAT", &dstatus,
"status of jitter data is good", &status) ;
/* close the output file */
FITS_close_file(outfits, &status) ;
/* free up storage space */
free(mjd) ;
free(fpdexp) ;
free(qvalid) ;
free(fq1) ;
free(fq2) ;
free(fq3) ;
free(aq1) ;
free(aq2) ;
free(aq3) ;
free(aattflg) ;
free(acscmd1) ;
free(acscmd2) ;
free(acscmd3) ;
free(time) ;
free(trakflg) ;
free(dq1) ;
free(dq2) ;
free(dq3) ;
free(dx) ;
free(dy) ;
cf_timestamp(CF_PRGM_ID, CF_VER_NUM, "Finished execution.");
return 0 ;
}
/* procedure to do a matrix multiplication of two quaturnians to determine
the displacement of a measured value from a reference */
int quatprod(double *tquat, double *quat_ref, double *dquat) {
int i, j ;
double multmat[4][4], qinv[4] ;
/* fill in the array with values from the tquat vector */
multmat[0][0] = tquat[3] ;
multmat[0][1] = -tquat[2] ;
multmat[0][2] = tquat[1] ;
multmat[0][3] = -tquat[0] ;
multmat[1][0] = tquat[2] ;
multmat[1][1] = tquat[3] ;
multmat[1][2] = -tquat[0] ;
multmat[1][3] = -tquat[1] ;
multmat[2][0] = -tquat[1] ;
multmat[2][1] = tquat[0] ;
multmat[2][2] = tquat[3] ;
multmat[2][3] = -tquat[2] ;
multmat[3][0] = tquat[0] ;
multmat[3][1] = tquat[1] ;
multmat[3][2] = tquat[2] ;
multmat[3][3] = tquat[3] ;
/* specify the inverse of quat_ref */
qinv[0] = -quat_ref[0] ;
qinv[1] = -quat_ref[1] ;
qinv[2] = -quat_ref[2] ;
qinv[3] = quat_ref[3] ;
/* do the matrix multiplication */
for (i=0 ; i<4 ; i++) {
dquat[i] = 0. ;
for (j=0; j<4 ; j++) dquat[i] = dquat[i] + multmat[j][i]*qinv[j] ;
}
return 0 ;
}
|