PDS_VERSION_ID = PDS3 RECORD_TYPE = STREAM OBJECT = TEXT PUBLICATION_DATE = 2002-01-31 NOTE = " DATATIPS.TXT provides quick-start help for anyone wanting to write software to make use of the Voyager PWS full-resolution uncalibrated data on this volume." END_OBJECT = TEXT END ======================================================================== DATA FILE OVERVIEW ======================================================================== The binary files containing the Voyager PWS full-resolution uncalibrated data are found under directories named DATA/FULL/Tyymm_mm where yy is the two-digit year and mm_mm indicates an inclusive range of four months. The data files are named Tyymmdd.DAT where yymmdd represents the year, month, and day (SCET) of data contained in the file. Each file record is 48 bytes in length, consisting of 24 low-byte-first (little-endian) 16-bit integer fields. The detailed description of these fields is contained in the file VGRPWSEL.FMT found in each data directory. This file along with corresponding Tyymmdd.LBL label files and the information in the CATALOG and DOCUMENT directories provide full details. ======================================================================== DATA PROCESSING OVERVIEW ======================================================================== The uncalibrated integer data numbers contained in these files are roughly proportional to the log of the voltage detected by the PWS instrument in each of 16 frequency channels ranging from 10 Hz to 56.2 kHz, logarithmically spaced, four per decade: Channel Center Frequency Bandwidth 1 10.0 Hz 2.99 Hz 2 17.8 Hz 3.77 Hz 3 31.1 Hz 7.50 Hz 4 56.2 Hz 10.06 Hz 5 100. Hz 13.3 Hz 6 178. Hz 29.8 Hz 7 311. Hz 59.5 Hz 8 562. Hz 106 Hz 9 1.00 kHz 133 Hz 10 1.78 kHz 211 Hz 11 3.11 kHz 298 Hz 12 5.62 kHz 421 Hz 13 10.0 kHz 943 Hz 14 17.8 kHz 2110 Hz 15 31.1 kHz 4210 Hz 16 56.2 kHz 5950 Hz Of the 24 16-bit LSB integer items in each record, the most useful are: Item Byte offset Description 1 0 SCET years past 1900 (2001 = 101) 2 2 SCET hour of year plus 24 3 4 SCET second of hour 4 6 SCET millisecond of second 9 16 data number from PWS channel 1 10 18 data number from PWS channel 2 . . . . . . . . . 24 46 data number from PWS channel 16 An ASCII text file included in each data directory contains a calibration table mapping each 8-bit instrument sample to a calibrated voltage. This file, VG1PWSCL.TAB, described in VGRPWSCL.FMT, may be read and further manipulated to produce a look-up table for other scientifically interesting units, such as: Electric field, V/m, calculated by dividing the values in VG1PWSCL.TAB by the effective electrical length of the PWS antenna, 7.07 meters; Spectral density, V**2/m**2/Hz, calculated by squaring the electric field and dividing by the noise bandwidth of the corresponding channel as given in the table above; Power flux, W/m**2/Hz, calculated by dividing the spectral density by the impedance of free space, 376.73 ohms. Special caveats include: 1. Only units proportional to power (or volts squared) are appropriate for averaging. 2. Some data numbers have been multiplied by -1 to indicate the presence of interference. 3. Data numbers for some telemetry modes are actually 10-bit sums of 4 instrument samples. 4. Zero data numbers indicate missing samples. Typical ways of graphing these data for analysis include: 1. An amplitude vs. frequency spectrum taken either from a single data record or averaged over a larger period of time. 2. An amplitude vs. time plot of the time evolution of the signal detected in a single frequency channel. 3. Combined amplitude vs. time plots from several or all channels, resulting in a representation of the time evolution of the spectrum across a range of frequencies. This is often presented as a "stacked histogram" or sometimes as a "spectrogram" with amplitude represented as color or shades of gray. The following annotated code illustrates how to extract calibrated values from these files. ======================================================================== 'C' CODE EXAMPLE ======================================================================== /* vg1pws.c /* /* Example 'C' code to extract Voyager 1 PWS full-resolution spectrum /* analyzer samples and list them as calibrated spectral density values /* along with spacecraft event time and telemetry mode information. /* This code constitutes a complete application and should work on any /* system with an ANSI C compiler regardless of machine byte order. /* /* On UNIX systems this example can be compiled with a command like: /* cc -O -o vg1pws vg1pws.c /* /* The calibration file VG1PWSCL.TAB is assumed to be in the current /* directory. /* /* Input is read from stdin and results are sent to stdout. /* Typical usage would be: /* vg1pws < T790305.DAT */ #include /* The following macros and tables could be saved in a separate header /* file for general use in other applications. */ /* fixed-length 48-byte records */ #define PWSA_RECSIZE 48 /* utility macros (use these to generate access macros, not directly in code) /* p is a buffer pointer of any type (pointing to the beginning of the record) /* i and j are high-order and low-order (respectively) byte offsets */ #define xINT1(p,i) ( (int)((unsigned char *)(p))[i] ) #define xINT2(p,i,j) ( xINT1(p,i) << 8 | xINT1(p,j) ) /* extract fields given a pointer to a record (assumes ints >= 32-bits) /* y1900 - years past 1900 (2001 = 101) /* hoy - hour of year beginning with 24 (so hoy / 24 = day of year) /* soh - second of hour /* msec - millisecond of second /* mod16 - FDS SCLK modulo 65536 (2**16) counter /* mod60 - FDS SCLK modulo 60 counter (increments every 48 seconds) /* line - FDS SCLK line counter (1-800) /* mode - telemetry mode /* sc - 1 for VG1 and 2 for VG2 (note arrays indexed with sc-1 ) */ #define PWSA_y1900(p) xINT2(p,1,0) #define PWSA_hoy(p) xINT2(p,3,2) #define PWSA_soh(p) xINT2(p,5,4) #define PWSA_msec(p) xINT2(p,7,6) #define PWSA_mod16(p) xINT2(p,9,8) #define PWSA_mod60(p) xINT2(p,11,10) #define PWSA_line(p) xINT2(p,13,12) #define PWSA_mode(p) xINT1(p,14) #define PWSA_sc(p) xINT1(p,15) /* PWSA_dn(p,c) returns data number bits as stored in the cd format given a /* pointer to a record "p" and a channel number "c" (0-15). Note that /* corrections must still be made for CR5A/UV5A 10-bit sums and for negative /* values. For 10-bit sums, simply divide the data number by 4.0. /* Some GS3 are tagged negative (for interference), but PWSA_dn will only /* return the least significant 16-bits of this. After "idn = PWSA_dn(p,c);" /* one might use "if (idn & 0x8000) idn = 0;" to ignore these or else /* "if (idn & 0x8000) idn |= 0xFFFF0000;" to sign extend for a 32-bit /* negative value. */ #define PWSA_dn(p,c) xINT2(p,((c)<<1)+17,((c)<<1)+16) /* more convenient derived time components */ #define PWSA_year(p) ( PWSA_y1900(p) + 1900 ) #define PWSA_day(p) ( PWSA_hoy(p) / 24 ) #define PWSA_hour(p) ( PWSA_hoy(p) % 24 ) #define PWSA_minute(p) ( PWSA_soh(p) / 60 ) #define PWSA_sec(p) ( PWSA_soh(p) % 60 ) #define PWSA_msod(p) ( PWSA_msec(p) + PWSA_soh(p) * 1000 + \ PWSA_hour(p) * 3600000 ) /* valid telemetry modes */ #define CR2 0x01 #define CR3 0x02 #define CR4 0x03 #define CR5 0x04 #define CR6 0x05 #define CR1 0x07 #define GS10A 0x08 #define GS3 0x0A #define GS7 0x0C #define GS6 0x0E #define OC2 0x16 #define OC1 0x17 #define CR5A 0x18 #define GS10 0x19 #define GS8 0x1A #define UV5A 0x1D static const char *TLM_mode_name[32] = { "ENG0","CR2","CR3","CR4","CR5","CR6","CR7","CR1", "GS10A","0x09","GS3","0x0B","GS7","0x0D","GS6","GS4", "0x10","GS2","0x12","0x13","0x14","0x15","OC2","OC1", "CR5A","GS10","GS8","0x1B","0x1C","UV5A","0x1E","0x1F" }; /* channel frequencies in Hz (indexed 0 - 15) */ static const double PWSA_freq[16] = { 10.0, 17.8, 31.1, 56.2, 100.0, 178.0, 311.0, 562.0, 1000.0, 1780.0, 3110.0, 5620.0, 10000.0, 17800.0, 31100.0, 56200.0 }; /* channel bandwidths in Hz, indexed by sc (0 - 1) and channel (0 - 15) */ static const double PWSA_bw[2][16] = { { 2.99, 3.77, 7.50,10.06, 13.3, 29.8, 59.5, 106., 133., 211., 298., 421., 943., 2110., 4210., 5950. }, { 2.16, 3.58, 4.50, 10.7, 13.8, 28.8, 39.8, 75.9, 75.9, 151., 324., 513., 832., 1260., 2400., 3800. } }; /* effective electrical length of antenna in meters */ #define PWS_elength 7.07 /* The following calibration function could be saved out in a separate /* source file for more convenient use in other applications. */ int vg1pwssd (const unsigned char *buf, double *sd) { /* Given a pointer to a 48-byte buffer containing a Voyager 1 PWS /* full-resolution uncalibrated data record and a pointer to a /* 16-element double precision array, fill the array with the /* corresponding calibrated spectral density (V**2/m**2/Hz) values. /* /* The calibration file VG1PWSCL.TAB is read from the current directory. /* /* Return 0 on success and non-zero on failure. */ static int loadtable = 1; /* flag to load calibration table */ FILE *calfp; /* calibration file pointer */ static double cal[256][16]; /* calibration table */ double value; /* calibrated value */ int dn[16]; /* array of uncalibrated samples */ int i, j, idata; /* loop indices and temp variables */ double data, y0, y1; /* used in linear interpolation */ /* Load calibration table once */ if (loadtable) { if (!(calfp = fopen("VG1PWSCL.TAB", "r"))) { fprintf (stderr, "ERROR opening VG1PWSCL.TAB\n"); return -1; } for (j = 0; j < 256; j++) { if (!fscanf (calfp, " %3d", &idata) || (idata != j)) { fprintf (stderr, "ERROR loading VG1PWSCL.TAB\n"); return -1; } for (i = 0; i < 16; i++) { if (!fscanf (calfp, ",%8lE", &value)) { fprintf (stderr, "ERROR reading VG1PWSCL.TAB\n"); return -1; } /* Convert volts to spectral density (V**2/m**2/Hz) and store */ cal[j][i] = (value * value) / (PWS_elength * PWS_elength) / PWSA_bw[0][i]; } /* for all 16 channels */ } /* for all 256 uncalibrated values */ fclose (calfp); loadtable = 0; } /* if table needs to be loaded */ /* Extract raw uncalibrated samples (data numbers, dn) */ for (i = 0; i < 16; i++) { dn[i] = PWSA_dn(buf,i); if (dn[i] & 0x8000) dn[i] = 0; /* zero flagged interference */ } /* Extract telemetry mode information and handle 10-bit sum cases */ switch (PWSA_mode(buf)) { /* 8-bit modes */ case CR2: case CR3: case CR4: case CR5: case CR6: case CR1: case GS10A: case GS3: case GS7: case GS6: case OC2: case OC1: case GS10: case GS8: for (i = 0; i < 16; i++) sd[i] = cal[dn[i]][i]; break; /* 10-bit sums of 4 instrument samples */ case CR5A: case UV5A: for (i = 0; i < 16; i++) { data = (double)dn[i] / 4.0; idata = (int)data; y0 = cal[idata][i]; y1 = cal[idata+1][i]; sd[i] = y0 + (y1 - y0) * (data - (double)idata); } break; default: fprintf (stderr, "ERROR unexpected telemetry mode %d\n", PWSA_mode(buf)); return -1; } /* switch on telemetry mode */ return 0; } /* vg1pwssd - extract calibrated spectral density */ /* The main program . . . */ int main (int argc, char *argv[]) { unsigned char rec[PWSA_RECSIZE]; /* fixed-length records */ unsigned long int count = 0; /* number of records processed */ int i; /* loop index */ double sd[16]; /* 16 channels of spectral density */ /* Loop through all available records from standard input */ while (fread (rec, PWSA_RECSIZE, 1, stdin)) { count++; printf ("\nRECORD %5ld ", count); /* Use convenience macros to extract SCET and SCLK */ printf (" SCET %04d %03d %02d:%02d:%02d.%03d ", PWSA_year(rec), PWSA_day(rec), PWSA_hour(rec), PWSA_minute(rec), PWSA_sec(rec), PWSA_msec(rec)); printf (" SCLK %05d.%02d.%03d ", PWSA_mod16(rec), PWSA_mod60(rec), PWSA_line(rec)); /* Telemetry mode and spacecraft number */ printf (" MODE %4s ", TLM_mode_name[PWSA_mode(rec)]); printf (" VG%d\n", PWSA_sc(rec)); /* Calibrated spectral density values */ if (vg1pwssd (rec, sd)) { fprintf (stderr, "ABORTING vg1pws\n"); exit (-1); } for (i = 0; i < 16; i++) { printf (" %8.2E", sd[i]); } printf ("\n"); } /* while data to read */ exit (0); } /* main - vg1pws example program */