PDS_VERSION_ID = PDS3 RECORD_TYPE = STREAM OBJECT = TEXT PUBLICATION_DATE = 2000-12-08 NOTE = " DATATIPS.TXT provides quick-start help for anyone wanting to write software to make use of the raw Voyager PWS waveform data on this volume." END_OBJECT = TEXT END ======================================================================== DATA FILE OVERVIEW ======================================================================== The binary files containing the raw Voyager PWS electric field waveform samples are found under directories named DATA/WFRM/Pn/V108nn where Pn indicates a spacecraft clock (SCLK) partition number and V108nn ranges from V10801 to V10835. The data files are named Cmmmmmnn.DAT where mmmmm is the SCLK modulo 65536 (16-bit) counter and nn is the SCLK modulo 60 counter. The modulo 60 counter changes once every 48 seconds and each data file contains all of the available waveform samples obtained during one of these 48 second intervals. A SCLK sub-interval called a line count ranges from 1 through 800 during this time and corresponds to each of the possible 800 data records within a file. Each file record is 1024 bytes in length and the first record is a header record which contains various engineering parameters, but no waveform data. Details about each file can be found in detached PDS labels named with corresponding SCLK values Cmmmmmnn.LBL The common description of the file header fields and record header fields can be found in each directory in files named WFENGHDR.FMT and WFROWPFX.FMT These files along with information in the CATALOG and DOCUMENT directories provide full details. ======================================================================== DATA PROCESSING OVERVIEW ======================================================================== There are generally two ways to use these data: 1. Plot, list, or listen to the time-domain electric field samples. 2. Plot or list the frequency-domain power spectra resulting from processing the electric field samples through an FFT. Although advanced analysis details are beyond the scope of this document, the most important first steps of extracting individual samples and associating them with time are addressed. The following facts are essential in using these data: 1. The electric field waveform samples are 4-bit values (range 0 - 15). 2. The amplitudes are modified by an AGC, so there is a varying amplitude scale. 3. There is no direct way to calibrate the samples to scientific units. 4. The sample rate is 28,800 samples per second. 5. The detector utilizes a bandpass of 40 Hz to 12 kHz. 6. Each line (record) contains 1600 continuous samples with a time gap equivalent to 128 missing samples before the next available line. The most important details needed to extract the waveform samples are: 1. Reliable information about an individual file can be found in an ASCII label beginning at byte 249 in the first record (where the first byte is byte 1). The format is: "VOYAGER-n PWS n/nnnnn.nn yyyy-mm-ddThh:mm:ss.sssZ" 2. The time offset of the beginning of a set of waveform samples (relative to the time in the ASCII label above) should be calculated from the SCLK line count, which is a 2-byte MSB integer beginning at byte 23 of data records. This offset is simply: 0.06 seconds * ( line - 1 ). 3. The 800 bytes holding 1600 4-bit waveform samples begins at byte 221 of each data record. The following annotated code illustrates how to extract the waveform samples. ======================================================================== 'C' CODE EXAMPLE ======================================================================== /* pwswfrmlist.c /* /* Example 'C' code to extract Voyager PWS waveform samples /* and list them as hexidecimal values along with a time offset. /* /* Input is read from stdin and results are sent to stdout. /* Typical usage would be: /* /* pwswfrmlist < C1234512.DAT */ #include int main (int argc, char *argv[]) { unsigned char rec[1024]; /* 1024 bytes per record */ int line; /* SCLK line count (60 ms) */ double offset; /* time offset in seconds */ int sample; /* an extracted wfrm sample */ int i; /* loop index */ char hex[] = /* hex characters */ {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; /* Read the first (Engineering header) record. */ if (fread (rec, sizeof(rec), 1, stdin) != 1) { fprintf (stderr, "Error reading engineering header record\n"); return -1; } /* The most useful (and reliable) information from the file header is /* the PWS ASCII label field which was added to the original EDR /* header beginning at byte 249. The format of this field is as /* follows: /* /* VOYAGER-n PWS n/nnnnn.nn yyyy-mm-ddThh:mm:ss.sssZ\0\0 /* /* where VOYAGER-n is either VOYAGER-1 or VOYAGER-2; /* n/nnnnn.nn is the spacecraft clock value (partition/mod16.mod60); /* yyyy-mm-ddThh:mm:ss.sssZ is the spacecraft event time (SCET) of the /* beginning of the 48-second interval (mod60 count). /* /* Print the information from the PWS ASCII label field. This should /* be parsed and saved for later use in less-trivial applications. /* Note that byte 249 is at 'C' index 248. */ fprintf (stdout, "%s\n", rec + 248); /* Now loop through all remaining data records. */ while (fread (rec, sizeof(rec), 1, stdin)) { /* Some files may have missing records, so the value of the SCLK /* line count should be used to determine the offset time of any /* record. The 2-byte MSB (big-endian) integer value for the line /* count occupies bytes 23 and 24 of every data record. The /* following method of extracting the 2-byte value should be /* independent of the host byte ordering. */ line = ( (int)rec[22] << 8 ) | (int)rec[23]; /* Time offset in seconds, relative to the value in the header, /* of the first sample in this record: */ offset = 0.06 * ( line - 1 ); fprintf (stdout, "%6.2f ", offset); /* Now loop through all 800 bytes (1600 4-bit samples) beginning at /* byte 221 in the record */ for (i = 220; i < 220 + 800; i++) { sample = (int)rec[i] >> 4; fprintf (stdout, "%c", hex[sample]); sample = (int)rec[i] & 0x0f; fprintf (stdout, "%c", hex[sample]); } fprintf (stdout, "\n"); } /* while data successfully read from standard input */ /* In some applications it may be useful to skip zero-filled or /* duplicate records, or skip the first 16 samples of each line. /* If the next step is an FFT, it may be useful to map the values /* to a set of floating point numbers ranging from, say, -7.5 to /* +7.5. Essentially, however, this example extracts all data for /* most purposes. */ return 0; } /* pwswfrmlist - example program */ ======================================================================== KODAK/RSI IDL CODE EXAMPLE ======================================================================== ; pwswfrmplot.pro ; ; Example Kodak/RSI IDL code to extract Voyager PWS waveform samples ; and plot the waveform and relative power spectrum of each of the lines ; of data in a given file. See the above 'C' example for more ; information. ; 4-bit waveform samples can be re-mapped to floating point -7.5 to 7.5 table = findgen(16) - 7.5 ; 1600 samples in time at 28,800 samples per second time = findgen(1600) / 28.8 ; in ms ; 801 frequency components will be produced by the FFT ; The highest frequency will be the Nyquist frequency (half the sample ; rate) freq = findgen(801) / 800. * 14.4 ; in kHz ; Input file name fname = 'C1622654.DAT' read, 'Enter input file name: ', fname openr, 1, fname ; 1024-byte records rec = bytarr(1024) ; Read the first (file header) record and extract the PWS ASCII label ; info. readu, 1, rec label = string(rec(248:298)) ; There will be 1600 4-bit waveform samples per record samples = intarr(1600) ; As an IDL trick, we'll use an array of the even indices in order ; to extract first the high 4-bit values and then the low 4-bit values even = indgen(800) * 2 ; Loop until there's a read error (usually 800 lines) on_ioerror, done while (1) do begin readu, 1, rec ; Extract the SCLK line count from bytes 23 and 24 (MSB 16-bit ; integer) line = fix(rec(22)) * 256 + fix(rec(23)) ; The time offset relative to the time in the label, in seconds offset = 0.06 * (line - 1) ; Extract the high-order 4-bit samples samples(even) = fix(rec(220:1019)) / 16 ; Then the interlaced low-order 4-bit samples samples(even+1) = fix(rec(220:1019)) mod 16 ; Two plots per page !p.multi = [0, 1, 2] ; Top plot is the waveform plot, time, samples, $ yrange=[0, 15], ystyle=1, $ xtitle="relative time [ms]", ytitle="amplitude", $ title=label + string(offset, format='(" +", f6.2, " sec")') ; Re-map the samples, multiply by a Hamming window, and transform. ; (Removing hanning() below will introduce noise due to the ; discontinuity between the ends of the sample window and will also ; affect the overall power amplitude, but is reasonable for quick-and- ; dirty analysis.) wfrm = table(samples) * hanning(n_elements(samples), alpha=0.54) spectrum = abs(fft(wfrm)) ; Bottom plot is the (uncalibrated) power spectrum plot, freq, spectrum(0:800), $ xrange=[0.04, 12.0], xstyle=1, xtitle="frequency [kHz]", $ yrange=[1.e-3, 10.0], ystyle=1, /ylog, ytitle="relative power" wait, 0.2 endwhile done: close, 1 end