OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
scqc_viirs.c
Go to the documentation of this file.
1 // Ported from IDL procedure to perform quality control on SNPP spacecraft packet data
2 // files. The output is written to STDOUT.
3 
4 // Arguments
5 //
6 // Name Type I/O Description
7 // ---- ---- --- -----------
8 // sfile string I S/C diary packet file name
9 // afile string I ADCS telemetry packet file name
10 // bfile string I Bus-critical telemetry packet file name
11 // gfile string I GPS telemetry packet file name (J2 only)
12 // rfile string O quality check output file
13 
14 // Liang Hong, July 22, 2015
15 // V0.1, Aug. 4, 2015
16 // Liang Hong, Aug. 9, 2016; V 0.2; added support for JPSS-1 VIIRS
17 // Liang Hong, Dec. 30, 2020; V1.0.0;
18 // -- err # from index 1;
19 // -- GPS telemetry input and QC added (J2)
20 // -- check for the J2 S/C ID and set packet sizes.
21 // -- sample rates for the diary and ADCS data are 10Hz for J2 vs. 1Hz for SNPP and J1, so the delta time limits are modified
22 // Liang Hong, Aug. 23, 2021; V1.1.0;
23 // -- read s/c diary data by each packet instead of whole file
24 
25 
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <libgen.h>
30 #include <timeutils.h>
31 
32 #define VERSION "1.1.0_2021-08-23"
33 
34 int main(int argc, char *argv[]) {
35  printf("scqc_viirs Version: %s (%s %s)\n", VERSION, __DATE__, __TIME__);
36  char *sfile, *afile, *bfile, *gfile, *rfile;
37  int c;
38  int bReportFile = 0;
39  int plat = -1; // platform identifier.
40  int scdpktsize = 71;
41  int apktsize;
42  int bpktsize;
43  int gpktsize;
44 
45  while ((c = getopt(argc, argv, "s:a:b:g:r:")) != -1)
46  switch (c) {
47  case 's':
48  sfile = optarg;
49  break;
50  case 'a':
51  afile = optarg;
52  break;
53  case 'b':
54  bfile = optarg;
55  break;
56  case 'g':
57  gfile = optarg;
58  break;
59  case 'r':
60  rfile = optarg;
61  bReportFile = 1;
62  break;
63  case '?':
64  if (optopt == 's')
65  fprintf(stderr, "Option -s requires an argument.\n");
66  else if (optopt == 'a')
67  fprintf(stderr, "Option -a requires an argument.\n");
68  else if (optopt == 'b')
69  fprintf(stderr, "Option -b requires an argument.\n");
70  else if (optopt == 'r')
71  fprintf(stderr, "Option -r requires an argument.\n");
72  else
73  fprintf(stderr,
74  "Unknown option character `\\x%x'.\n",
75  optopt);
76  return 1;
77  default:
78  abort();
79  }
80  if (sfile == NULL || afile == NULL || bfile == NULL || rfile == NULL) {
81  printf("unable to open input files.\n");
82  printf("usage: scqc_viirs -s S/C_diary_file -a ADCS_file -b S/C_bus_file [-g GPS_file] -r QC_report_file\n");
83  return 1;
84  }
85 
86  FILE *infile, *infile_a, *infile_b, *infile_g, *outfile;
87  infile = fopen(sfile, "r");
88  printf("Opened S/C diary packet file %s\n", sfile);
89  struct stat st;
90  stat(sfile, &st);
91  int nscd = st.st_size / scdpktsize;
92  uint8_t scdpkts[scdpktsize];
93  fread(scdpkts, 1, scdpktsize, infile);
94  //fclose(infile);
95  // convert_diary,nscd,scdpkts,iyrsc,idysc,otime,orb,atime,quat
96 
97  // Check spacecraft ID
98  if (scdpkts[14] == 157) {
99  plat = 0;
100  apktsize = 355;
101  bpktsize = 207;
102  // scanp = 1.7793
103  }
104  if (scdpkts[14] == 159) {
105  plat = 1;
106  apktsize = 393;
107  bpktsize = 183;
108  // scanp 1.7864
109  }
110  if (scdpkts[14] == 177) {
111  plat = 2;
112  apktsize = 493;
113  bpktsize = 212;
114  gpktsize = 374;
115  // scanp 1.7864
116 
117  // quit with error message if JPSS-2 is being processed without gps file as input
118  if (gfile == NULL) {
119  printf("missing gps file for JPSS-2 (P177).\n");
120  printf("usage: scqc_viirs -s S/C_diary_file -a ADCS_file -b S/C_bus_file -g GPS_file -r QC_report_file\n");
121  return 1;
122  }
123  }
124 
125  infile_a = fopen(afile, "r");
126  printf("Opened ADCS telemetry packet file %s\n", afile);
127  stat(afile, &st);
128  int nadc = st.st_size / apktsize;
129  uint8_t adcpkts[apktsize];
130 
131  infile_b = fopen(bfile, "r");
132  printf("Opened bus-critical telemetry packet file %s\n", bfile);
133  stat(bfile, &st);
134  int nbus = st.st_size / bpktsize;
135  uint8_t buspkts[bpktsize];
136 
137  int ngps = 0;
138  if (plat >= 2) {
139  infile_g = fopen(gfile, "r");
140  printf("Opened GPS telemetry packet file %s\n\n", gfile);
141  stat(gfile, &st);
142  ngps = st.st_size / gpktsize;
143  }
144 
145  // open report file
146  if (bReportFile) {
147  outfile = fopen(rfile, "a+");
148  if (outfile == NULL) {
149  printf("Unable to open output report file.\n");
150  return 1;
151  }
152  fprintf(outfile, "scdiary_basename=%s\n", basename(sfile));
153  fprintf(outfile, "adcs_basename=%s\n", basename(afile));
154  fprintf(outfile, "btlm_basename=%s\n", basename(bfile));
155  if (plat >= 2)
156  fprintf(outfile, "gps_basename=%s\n", basename(gfile));
157  }
158 
159  double scdtime[nscd], adctime[nadc], bustime[nbus], gpstime[ngps], delt[2], dtime;
160 
161  // Get start year and day
162 
163  int32_t jd0, iyr, iday;
164  jd0 = (scdpkts[6] << 8) + (scdpkts[7]) + 2436205;
165  jdate(jd0, &iyr, &iday);
166 
167  // Loop through packets and extract times
168  // S/C diary
169  int16_t iy, ih, mn, mm, dd;
170  int32_t ccsds_iy, idy, jd;
171  int i, m;
172  int ierr = 0;
173  int itimegaps = 0;
174  double sec, secd, usec;
175  uint8_t cctime[8];
176  char *errstr = (char*) malloc(10000 * 100); // string array to store errors
177 
178  if (plat <= 1) {
179  delt[0] = 0.9;
180  delt[1] = 1.1;
181  } else {
182  delt[0] = 0.09;
183  delt[1] = 0.11;
184  }
185 
186  for (m = 0; m < 8; m++) cctime[m] = scdpkts[m + 6];
187  ccsds_to_yds(cctime, &ccsds_iy, &idy, &secd);
188  iy = (int16_t) ccsds_iy;
189  jd = jday((int32_t) iy, 1, idy);
190  scdtime[0] = secd + (jd - jd0)*86400;
191  //sod2hms((int)secd,&ih,&mn,&sec);
192  usec = yds2unix(iy, idy, secd);
193  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
194  printf("S/C diary start date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
195  if (bReportFile) {
196  sec = floor(sec * 1000) / 1000;
197  fprintf(outfile, "scdiary_start_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
198  }
199 
200  for (i = 1; i < nscd; i++) {
201  fread(scdpkts, 1, scdpktsize, infile);
202  for (m = 0; m < 8; m++) cctime[m] = scdpkts[m + 6];
203  ccsds_to_yds(cctime, &ccsds_iy, &idy, &secd);
204  iy = (int16_t) ccsds_iy;
205  jd = jday((int32_t) iy, 1, idy);
206  scdtime[i] = secd + (jd - jd0)*86400;
207  dtime = scdtime[i] - scdtime[i - 1];
208  if ((dtime < delt[0]) || (dtime > delt[1])) {
209  //sod2hms((int)secd,&ih,&mn,&sec);
210  usec = yds2unix(iy, idy, secd);
211  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
212  char tmpstr[100];
213  sprintf(tmpstr, "Time difference %f at record %d, at%02d:%02d:%02d", dtime, i, ih, mn, (int) sec);
214  strcpy(&errstr[ierr * 100], tmpstr);
215  printf("%s\n", tmpstr);
216  itimegaps++;
217  ierr++;
218  }
219  }
220  fclose(infile);
221 
222  //sod2hms((int)secd,&ih,&mn,&sec);
223  usec = yds2unix(iy, idy, secd);
224  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
225  printf("S/C diary end date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
226  printf("%d records processed\n\n", nscd);
227  if (bReportFile) {
228  sec = floor(sec * 1000) / 1000;
229  fprintf(outfile, "scdiary_stop_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
230  fprintf(outfile, "scdiary_records=%d\n", nscd);
231  fprintf(outfile, "scdiary_errors=%d\n", ierr);
232  fprintf(outfile, "scdiary_timegap_records=%d\n", itimegaps);
233  for (i = 0; i < ierr; i++) {
234  fprintf(outfile, "scdiary_err_%d=%.*s\n", i+1, 100, errstr + i * 100);
235  }
236  }
237 
238  // ADCS
239  ierr = 0;
240  itimegaps = 0;
241  free(errstr);
242  errstr = (char*) malloc(10000 * 100);
243  for (i = 0; i < nadc; i++) {
244  fread(adcpkts, 1, apktsize, infile_a);
245  for (m = 0; m < 8; m++) cctime[m] = adcpkts[m + 6];
246  ccsds_to_yds(cctime, &ccsds_iy, &idy, &secd);
247  iy = (int16_t) ccsds_iy;
248  jd = jday((int32_t) iy, 1, idy);
249  adctime[i] = secd + (jd - jd0)*86400;
250  if (i == 0) {
251  //sod2hms((int)secd,&ih,&mn,&sec);
252  usec = yds2unix(iy, idy, secd);
253  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
254  printf("ADCS start date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
255  if (bReportFile) {
256  sec = floor(sec * 1000) / 1000;
257  fprintf(outfile, "adcs_start_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
258  }
259  } else {
260  dtime = adctime[i] - adctime[i - 1];
261  if ((dtime < delt[0]) || (dtime > delt[1])) {
262  //sod2hms((int)secd,&ih,&mn,&sec);
263  usec = yds2unix(iy, idy, secd);
264  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
265  char tmpstr[100];
266  sprintf(tmpstr, "Time difference %f at record %d, at%02d:%02d:%02d", dtime, i, ih, mn, (int) sec);
267  strcpy(&errstr[ierr * 100], tmpstr);
268  printf("%s\n", tmpstr);
269  itimegaps++;
270  ierr++;
271  }
272  }
273  }
274  fclose(infile_a);
275 
276  //sod2hms((int)secd,&ih,&mn,&sec);
277  usec = yds2unix(iy, idy, secd);
278  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
279  printf("ADCS end date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
280  printf("%d records processed\n\n", nadc);
281  if (bReportFile) {
282  sec = floor(sec * 1000) / 1000;
283  fprintf(outfile, "adcs_stop_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
284  fprintf(outfile, "adcs_records=%d\n", nadc);
285  fprintf(outfile, "adcs_errors=%d\n", ierr);
286  fprintf(outfile, "adcs_timegap_records=%d\n", itimegaps);
287  for (i = 0; i < ierr; i++) {
288  fprintf(outfile, "adcs_err_%d=%.*s\n", i+1, 100, errstr + i * 100);
289  }
290  }
291 
292  // Bus-critical
293  ierr = 0;
294  itimegaps = 0;
295  free(errstr);
296  errstr = (char*) malloc(10000 * 100);
297  for (i = 0; i < nbus; i++) {
298  fread(buspkts, 1, bpktsize, infile_b);
299  for (m = 0; m < 8; m++) cctime[m] = buspkts[m + 6];
300  ccsds_to_yds(cctime, &ccsds_iy, &idy, &secd);
301  iy = (int16_t) ccsds_iy;
302  jd = jday((int32_t) iy, 1, idy);
303  bustime[i] = secd + (jd - jd0)*86400;
304  if (i == 0) {
305  //sod2hms((int)secd,&ih,&mn,&sec);
306  usec = yds2unix(iy, idy, secd);
307  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
308  printf("Bus-critical start date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
309  if (bReportFile) {
310  sec = floor(sec * 1000) / 1000;
311  fprintf(outfile, "btlm_start_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
312  }
313  } else {
314  dtime = bustime[i] - bustime[i - 1];
315  if ((dtime < 0.9) || (dtime > 1.1)) {
316  //sod2hms((int)secd,&ih,&mn,&sec);
317  usec = yds2unix(iy, idy, secd);
318  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
319  char tmpstr[100];
320  sprintf(tmpstr, "Time difference %f at record %d, at%02d:%02d:%02d", dtime, i, ih, mn, (int) sec);
321  strcpy(&errstr[ierr * 100], tmpstr);
322  printf("%s\n", tmpstr);
323  itimegaps++;
324  ierr++;
325  }
326  }
327  }
328  fclose(infile_b);
329 
330  //sod2hms((int)secd,&ih,&mn,&sec);
331  usec = yds2unix(iy, idy, secd);
332  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
333  printf("Bus-critical end date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
334  printf("%d records processed\n\n", nbus);
335  if (bReportFile) {
336  sec = floor(sec * 1000) / 1000;
337  fprintf(outfile, "btlm_stop_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
338  fprintf(outfile, "btlm_records=%d\n", nbus);
339  fprintf(outfile, "btlm_errors=%d\n", ierr);
340  fprintf(outfile, "btlm_timegap_records=%d\n", itimegaps);
341  for (i = 0; i < ierr; i++) {
342  fprintf(outfile, "btlm_err_%d=%.*s\n", i+1, 100, errstr + i * 100);
343  }
344  }
345 
346  // GPS
347  if (plat >= 2 && gfile != NULL) {
348  uint8_t gpspkts[gpktsize];
349  ierr = 0;
350  itimegaps = 0;
351  free(errstr);
352  errstr = (char*) malloc(10000 * 100);
353  for (i = 0; i < ngps; i++) {
354  fread(gpspkts, 1, gpktsize, infile_g);
355  for (m = 0; m < 8; m++) cctime[m] = gpspkts[m + 6];
356  ccsds_to_yds(cctime, &ccsds_iy, &idy, &secd);
357  iy = (int16_t) ccsds_iy;
358  jd = jday((int32_t) iy, 1, idy);
359  gpstime[i] = secd + (jd - jd0)*86400;
360  if (i == 0) {
361  //sod2hms((int)secd,&ih,&mn,&sec);
362  usec = yds2unix(iy, idy, secd);
363  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
364  printf("GPS start date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
365  if (bReportFile) {
366  sec = floor(sec * 1000) / 1000;
367  fprintf(outfile, "gps_start_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
368  }
369  } else {
370  dtime = gpstime[i] - gpstime[i - 1];
371  if ((dtime < 0.9) || (dtime > 1.1)) {
372  //sod2hms((int)secd,&ih,&mn,&sec);
373  usec = yds2unix(iy, idy, secd);
374  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
375  char tmpstr[100];
376  sprintf(tmpstr, "Time difference %f at record %d, at%02d:%02d:%02d", dtime, i, ih, mn, (int) sec);
377  strcpy(&errstr[ierr * 100], tmpstr);
378  printf("%s\n", tmpstr);
379  itimegaps++;
380  ierr++;
381  }
382  }
383  }
384  fclose(infile_g);
385 
386  //sod2hms((int)secd,&ih,&mn,&sec);
387  usec = yds2unix(iy, idy, secd);
388  unix2ymdhms(usec, &iy, &mm, &dd, &ih, &mn, &sec);
389  printf("GPS end date and time, year = %d, day = %d, hour = %d, min = %d, sec = %d\n", iy, idy, ih, mn, (int) sec);
390  printf("%d records processed\n\n", ngps);
391  if (bReportFile) {
392  sec = floor(sec * 1000) / 1000;
393  fprintf(outfile, "gps_stop_time=%4d-%02d-%02dT%02d:%02d:%06.3fZ\n", iy, mm, dd, ih, mn, sec);
394  fprintf(outfile, "gps_records=%d\n", ngps);
395  fprintf(outfile, "gps_errors=%d\n", ierr);
396  fprintf(outfile, "gps_timegap_records=%d\n", itimegaps);
397  for (i = 0; i < ierr; i++) {
398  fprintf(outfile, "gps_err_%d=%.*s\n", i+1, 100, errstr + i * 100);
399  }
400  }
401 
402  } // if (plat >= 2)
403 
404  if (bReportFile) fclose(outfile);
405  free(errstr);
406  return 0;
407 }
408 
double yds2unix(int16_t year, int16_t day, double secs)
Definition: yds2unix.c:7
function jd(i, j, k)
Definition: jd.f:2
#define VERSION
Definition: scqc_viirs.c:32
#define NULL
Definition: decode_rs.h:63
int jdate(int32_t julian, int32_t *year, int32_t *doy)
Definition: jdate.c:5
int32_t jday(int16_t i, int16_t j, int16_t k)
Definition: jday.c:4
int ccsds_to_yds(uint8_t *cctime, int32_t *iyear, int32_t *iday, double *sec)
Definition: ccsds_to_yds.c:5
int main(int argc, char *argv[])
Definition: scqc_viirs.c:34
Definition: jd.py:1
int32_t ih
Definition: atrem_corl1.h:161
char bfile[412]
Definition: hist.c:15
#define basename(s)
Definition: l0chunk_modis.c:29
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
int32_t idy
Definition: atrem_corl1.h:161
void unix2ymdhms(double usec, int16_t *year, int16_t *mon, int16_t *day, int16_t *hour, int16_t *min, double *sec)
Definition: unix2ymdhms.c:8
int i
Definition: decode_rs.h:71
How many dimensions is the output array Default is Not sure if anything above will work correctly strcpy(l2prod->title, "no title yet")
int32_t iyr
Definition: atrem_corl1.h:161