X-Git-Url: http://pileus.org/git/?p=~andy%2Frsl;a=blobdiff_plain;f=wsr88d_m31.c;h=3cd4f4cfb86418cbcc74a2065e3b2aabd3a391eb;hp=3c260a711bef0c444b46a4afdb11ec79358d4694;hb=da18c5859f2c4b449544ed9c5d2a96a53d43f377;hpb=012916676d26251849e408aaf574458e196df2c4 diff --git a/wsr88d_m31.c b/wsr88d_m31.c index 3c260a7..3cd4f4c 100644 --- a/wsr88d_m31.c +++ b/wsr88d_m31.c @@ -6,28 +6,33 @@ SSAI Lanham, Maryland - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. - This program is distributed in the hope that it will be useful, + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program. If not, see . + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + Boston, MA 02110-1301, USA. */ /* * This file contains routines for processing Message Type 31, the digital - * radar message type introduced in WSR-88D Level II Build 10. + * radar message type introduced in WSR-88D Level II Build 10. For more + * information, see the "Interface Control Document for the RDA/RPG" at the + * WSR-88D Radar Operations Center web site. */ #include "rsl.h" #include "wsr88d.h" +#include /* Data descriptions in the following data structures are from the "Interface * Control Document for the RDA/RPG", Build 10.0 Draft, WSR-88D Radar @@ -35,17 +40,15 @@ */ typedef struct { - short rpg[6]; /* Unused. Not really part of message header, but is - * inserted by RPG Communications Manager for each message. - */ - unsigned short msg_size; /* for this segment, in halfwords */ + short rpg[6]; /* 12 bytes inserted by RPG Communications Mgr. Ignored. */ + unsigned short msg_size; /* Message size for this segment, in halfwords */ unsigned char channel; /* RDA Redundant Channel */ - unsigned char msg_type; /* Message Type */ - unsigned short id_seq; /* I.d. Seq = 0 to 7FFF, then roll over to 0 */ - unsigned short msg_date; /* modified Julian date from 1/1/70 */ - unsigned int msg_time; /* packet generation time in ms past midnite */ - unsigned short num_segs; - unsigned short seg_num; + unsigned char msg_type; /* Message type. For example, 31 */ + unsigned short id_seq; /* Msg seq num = 0 to 7FFF, then roll over to 0 */ + unsigned short msg_date; /* Modified Julian date from 1/1/70 */ + unsigned int msg_time; /* Packet generation time in ms past midnight */ + unsigned short num_segs; /* Number of segments for this message */ + unsigned short seg_num; /* Number of this segment */ } Wsr88d_msg_hdr; typedef struct { @@ -65,16 +68,16 @@ typedef struct { unsigned char radial_spot_blanking; unsigned char azm_indexing_mode; unsigned short data_block_count; - /* Data Block Pointers */ - unsigned int dbptr_vol_const; - unsigned int dbptr_elev_const; - unsigned int dbptr_radial_const; - unsigned int dbptr_ref; - unsigned int dbptr_vel; - unsigned int dbptr_sw; - unsigned int dbptr_zdr; - unsigned int dbptr_phi; - unsigned int dbptr_rho; + /* Data Block Indexes */ + unsigned int vol_const; + unsigned int elev_const; + unsigned int radial_const; + unsigned int field1; + unsigned int field2; + unsigned int field3; + unsigned int field4; + unsigned int field5; + unsigned int field6; } Ray_header_m31; /* Called Data Header Block in RDA/RPG document. */ typedef struct { @@ -91,32 +94,15 @@ typedef struct { float offset; } Data_moment_hdr; -typedef struct { - Data_moment_hdr data_hdr; - /* TODO: data type will need to be changed to "void" to handle Dual Pole: - * some data are in 2-byte words. - */ - unsigned char *data; -} Data_moment; +#define MAX_RADIAL_LENGTH 14288 typedef struct { Ray_header_m31 ray_hdr; - short unamb_rng; - short nyq_vel; - /* Pointers to data */ - /* TODO: Replace data moment pointers with single pointer to radial. - * Can simply make unsigned char array as in MSG1 version. - * Maximum radial length is 14288 bytes. - */ - Data_moment *ref; - Data_moment *vel; - Data_moment *sw; + float unamb_rng; + float nyq_vel; + unsigned char data[MAX_RADIAL_LENGTH]; } Wsr88d_ray_m31; -#define MAXRAYS_M31 800 -#define MAXSWEEPS 20 - -enum {START_OF_ELEV, INTERMED_RADIAL, END_OF_ELEV, BEGIN_VOS, END_VOS}; void wsr88d_swap_m31_hdr(Wsr88d_msg_hdr *msghdr) @@ -130,24 +116,24 @@ void wsr88d_swap_m31_hdr(Wsr88d_msg_hdr *msghdr) } -void wsr88d_swap_m31_ray(Ray_header_m31 *wsr88d_ray) +void wsr88d_swap_m31_ray_hdr(Ray_header_m31 *ray_hdr) { - int *fullword; - - swap_4_bytes(&wsr88d_ray->ray_time); - swap_2_bytes(&wsr88d_ray->ray_date); - swap_2_bytes(&wsr88d_ray->azm_num); - swap_4_bytes(&wsr88d_ray->azm); - swap_2_bytes(&wsr88d_ray->radial_len); - swap_4_bytes(&wsr88d_ray->elev); - swap_2_bytes(&wsr88d_ray->data_block_count); - fullword = (int *) &wsr88d_ray->dbptr_vol_const; - for (; fullword <= (int *) &wsr88d_ray->dbptr_rho; fullword++) - swap_4_bytes(fullword); + int *data_ptr; + + swap_4_bytes(&ray_hdr->ray_time); + swap_2_bytes(&ray_hdr->ray_date); + swap_2_bytes(&ray_hdr->azm_num); + swap_4_bytes(&ray_hdr->azm); + swap_2_bytes(&ray_hdr->radial_len); + swap_4_bytes(&ray_hdr->elev); + swap_2_bytes(&ray_hdr->data_block_count); + data_ptr = (int *) &ray_hdr->vol_const; + for (; data_ptr <= (int *) &ray_hdr->field6; data_ptr++) + swap_4_bytes(data_ptr); } -void wsr88d_swap_data_moment(Data_moment_hdr *this_field) +void wsr88d_swap_data_hdr(Data_moment_hdr *this_field) { short *halfword; halfword = (short *) &this_field->ngates; @@ -158,25 +144,6 @@ void wsr88d_swap_data_moment(Data_moment_hdr *this_field) } -void testprt(Ray_header_m31 ray_hdr) -{ - /* For testing: Print some values from data block header. */ - printf("\nray_time: %d\n",ray_hdr.ray_time); - printf("ray_date: %d\n",ray_hdr.ray_date); - printf("azm_num: %d\n",ray_hdr.azm_num); - printf("azm: %f\n",ray_hdr.azm); - printf("radial_len: %d\n",ray_hdr.radial_len); - printf("elev: %f\n",ray_hdr.elev); - printf("data block count: %d\n",ray_hdr.data_block_count); - printf("dbptr_vol_const: %d\n",ray_hdr.dbptr_vol_const); - printf("dbptr_elev_const: %d\n",ray_hdr.dbptr_elev_const); - printf("dbptr_radial_const: %d\n",ray_hdr.dbptr_radial_const); - printf("dbptr_ref: %d\n",ray_hdr.dbptr_ref); - printf("dbptr_vel: %d\n",ray_hdr.dbptr_vel); - printf("dbptr_sw: %d\n",ray_hdr.dbptr_sw); -} - - float wsr88d_get_angle(short bitfield) { short mask = 1; @@ -185,7 +152,7 @@ float wsr88d_get_angle(short bitfield) float value[13] = {0.043945, 0.08789, 0.17578, 0.35156, .70313, 1.40625, 2.8125, 5.625, 11.25, 22.5, 45., 90., 180.}; - /* find which bits are set and sum corresponding values to get angle. */ + /* Find which bits are set and sum corresponding values to get angle. */ bitfield = bitfield >> 3; /* 3 least significant bits aren't used. */ for (i = 0; i < 13; i++) { @@ -273,219 +240,79 @@ void wsr88d_get_vcp_data(short *msgtype5) } -Data_moment *read_data_moment(unsigned char *radial, int begin_data_block) +void get_wsr88d_unamb_and_nyq_vel(Wsr88d_ray_m31 *wsr88d_ray, float *unamb_rng, + float *nyq_vel) { - Data_moment *this_field; - unsigned char* data; - unsigned char* dptr; - int hdr_size, n; - - /* - printf("read_data_moment: "); - printf("sizeof(Data_moment) = %d\n", sizeof(Data_moment)); - printf("sizeof(Data_moment_hdr) = %d\n", sizeof(Data_moment_hdr)); - */ - this_field = malloc(sizeof(Data_moment)); - hdr_size = sizeof(Data_moment_hdr); - /* printf("hdr_size = %d\n", hdr_size); */ - - dptr = radial + begin_data_block; - memcpy(&this_field->data_hdr, dptr, hdr_size); - dptr += hdr_size; - - if (little_endian()) wsr88d_swap_data_moment(&this_field->data_hdr); - data = (unsigned char *) malloc(this_field->data_hdr.ngates); - memcpy(data, dptr, this_field->data_hdr.ngates); - this_field->data = data; - return this_field; + int dindex, found; + short nyq_vel_sh, unamb_rng_sh; + + found = 0; + dindex = wsr88d_ray->ray_hdr.radial_const; + if (strncmp((char *) &wsr88d_ray->data[dindex], "RRAD", 4) == 0) found = 1; + else { + dindex = wsr88d_ray->ray_hdr.elev_const; + if (strncmp((char *) &wsr88d_ray->data[dindex], "RRAD", 4) == 0) + found = 1; + else { + dindex = wsr88d_ray->ray_hdr.vol_const; + if (strncmp((char *) &wsr88d_ray->data[dindex], "RRAD", 4) == 0) + found = 1; + } + } + if (found) { + memcpy(&unamb_rng_sh, &wsr88d_ray->data[dindex+6], 2); + memcpy(&nyq_vel_sh, &wsr88d_ray->data[dindex+16], 2); + if (little_endian()) { + swap_2_bytes(&unamb_rng_sh); + swap_2_bytes(&nyq_vel_sh); + } + *unamb_rng = unamb_rng_sh / 10.; + *nyq_vel = nyq_vel_sh / 100.; + } else { + *unamb_rng = 0.; + *nyq_vel = 0.; + } } int read_wsr88d_ray_m31(Wsr88d_file *wf, int msg_size, Wsr88d_ray_m31 *wsr88d_ray) { - Ray_header_m31 ray_hdr; - int n, begin_data_block, bytes_to_read, ray_hdr_len; - unsigned char *radial; - - /* Read ray data header block */ - n = fread(&wsr88d_ray->ray_hdr, sizeof(Ray_header_m31), 1, wf->fptr); - if (n < 1) { - fprintf(stderr,"read_wsr88d_ray_m31: Read failed.\n"); - return 0; - } - if (little_endian()) wsr88d_swap_m31_ray(&wsr88d_ray->ray_hdr); + int n; + float nyq_vel, unamb_rng; - ray_hdr = wsr88d_ray->ray_hdr; - - /* - if (ray_hdr.azm_num == 1) testprt(wsr88d_ray->ray_hdr); - */ - - ray_hdr_len = sizeof(ray_hdr); - - /* Read in radial - * Use header_size offset with data pointers - * Copy data into structures - */ + /* Read wsr88d ray. */ - bytes_to_read = msg_size - ray_hdr_len; - radial = (unsigned char *) malloc(bytes_to_read); - n = fread(radial, bytes_to_read, 1, wf->fptr); + n = fread(wsr88d_ray->data, msg_size, 1, wf->fptr); if (n < 1) { fprintf(stderr,"read_wsr88d_ray_m31: Read failed.\n"); return 0; } + /* Copy data header block to ray header structure. */ + memcpy(&wsr88d_ray->ray_hdr, &wsr88d_ray->data, sizeof(Ray_header_m31)); - if (ray_hdr.dbptr_radial_const != 0) { - begin_data_block = ray_hdr.dbptr_radial_const - ray_hdr_len; - memcpy(&wsr88d_ray->unamb_rng, &radial[begin_data_block+6], 2); - memcpy(&wsr88d_ray->nyq_vel, &radial[begin_data_block+16], 2); - if (little_endian()) { - swap_2_bytes(&wsr88d_ray->unamb_rng); - swap_2_bytes(&wsr88d_ray->nyq_vel); - } - } - else { - wsr88d_ray->unamb_rng = 0; - wsr88d_ray->nyq_vel = 0; - } - - if (ray_hdr.dbptr_ref != 0) { - begin_data_block = ray_hdr.dbptr_ref - ray_hdr_len; - wsr88d_ray->ref = read_data_moment(radial, begin_data_block); - } - if (ray_hdr.dbptr_vel != 0) { - begin_data_block = ray_hdr.dbptr_vel - ray_hdr_len; - wsr88d_ray->vel = read_data_moment(radial, begin_data_block); - } - if (ray_hdr.dbptr_sw != 0) { - begin_data_block = ray_hdr.dbptr_sw - ray_hdr_len; - wsr88d_ray->sw = read_data_moment(radial, begin_data_block); - } - + if (little_endian()) wsr88d_swap_m31_ray_hdr(&wsr88d_ray->ray_hdr); - /* For testing: print reflectivity data. */ - int prtdata = 0; - { int i; - if (prtdata) { - for (i=0; i < wsr88d_ray->ref->data_hdr.ngates; i++) { - if (i % 10 == 0) printf("\n"); - printf(" %d", wsr88d_ray->ref->data[i]); - } - printf("\n"); - } - } - - free(radial); - return 1; -} - - -void wsr88d_load_ray_data(Data_moment *data_block, Ray *ray) -{ - Data_moment_hdr data_hdr; - int ngates; - int i; - float value, scale, offset; - unsigned char *data; - Range (*invf)(float x); - float (*f)(Range x); - - data_hdr = data_block->data_hdr; - data = data_block->data; - - /* - printf("wsr88d_load_ray_data: "); - printf(" DataName: %s\n", data_hdr.dataname); - */ - - ngates = data_hdr.ngates; - /* - printf(" ngates = %d\n", ngates); - printf(" scale = %f\n", data_hdr.scale); - printf(" offset = %f\n", data_hdr.offset); - */ - offset = data_hdr.offset; - scale = data_hdr.scale; - - /* Note: data range is 2-255. 0 means signal is below threshold, and 1 - * means range folded. + /* Retrieve unambiguous range and Nyquist velocity here so that we don't + * have to do it for each data moment later. */ + get_wsr88d_unamb_and_nyq_vel(wsr88d_ray, &unamb_rng, &nyq_vel); + wsr88d_ray->unamb_rng = unamb_rng; + wsr88d_ray->nyq_vel = nyq_vel; - /* Test print - for (i=0; i < 10; i++) { - value = (data[i] - offset) / scale; - printf(" bytevalue = %d, value = %f\n", data[i], value); - } - */ - - /* Reflectivity */ - if (strncmp(data_hdr.dataname, "DREF", 4) == 0) { - /* convert data to float - * convert float to range and put in ray.range - */ - f = DZ_F; - invf = DZ_INVF; - for (i = 0; i < ngates; i++) { - if (data[i] > 1) - value = (data[i] - offset) / scale; - else value = (data[i] == 0) ? BADVAL : RFVAL; - ray->range[i] = invf(value); - ray->h.f = f; - ray->h.invf = invf; - } - } - - /* Velocity */ - if (strncmp(data_hdr.dataname, "DVEL", 4) == 0) { - /* convert data to float - * convert float to range and put in ray.range - */ - f = VR_F; - invf = VR_INVF; - for (i = 0; i < ngates; i++) { - if (data[i] > 1) - value = (data[i] - offset) / scale; - else value = (data[i] == 0) ? BADVAL : RFVAL; - ray->range[i] = invf(value); - ray->h.f = f; - ray->h.invf = invf; - } - } - - /* Spectrum Width */ - if (strncmp(data_hdr.dataname, "DSW", 3) == 0) { - /* convert data to float - * convert float to range and put in ray.range - */ - f = SW_F; - invf = SW_INVF; - for (i = 0; i < ngates; i++) { - if (data[i] > 1) - value = (data[i] - offset) / scale; - else value = (data[i] == 0) ? BADVAL : RFVAL; - ray->range[i] = invf(value); - ray->h.f = f; - ray->h.invf = invf; - } - } - ray->h.range_bin1 = data_hdr.range_first_gate; - ray->h.gate_size = data_hdr.range_samp_interval; - ray->h.nbins = ngates; + return 1; } - -void wsr88d_load_ray_hdr(Wsr88d_ray_m31 wsr88d_ray, Ray *ray) +void wsr88d_load_ray_hdr(Wsr88d_ray_m31 *wsr88d_ray, Ray *ray) { int month, day, year, hour, minute, sec; float fsec; Wsr88d_ray m1_ray; Ray_header_m31 ray_hdr; - ray_hdr = wsr88d_ray.ray_hdr; + ray_hdr = wsr88d_ray->ray_hdr; m1_ray.ray_date = ray_hdr.ray_date; m1_ray.ray_time = ray_hdr.ray_time; @@ -501,183 +328,188 @@ void wsr88d_load_ray_hdr(Wsr88d_ray_m31 wsr88d_ray, Ray *ray) ray->h.ray_num = ray_hdr.azm_num; ray->h.elev = ray_hdr.elev; ray->h.elev_num = ray_hdr.elev_num; - ray->h.unam_rng = wsr88d_ray.unamb_rng / 10.; - ray->h.nyq_vel = wsr88d_ray.nyq_vel / 100.; + ray->h.unam_rng = wsr88d_ray->unamb_rng; + ray->h.nyq_vel = wsr88d_ray->nyq_vel; int elev_index; elev_index = ray_hdr.elev_num - 1; ray->h.azim_rate = vcp_data.azim_rate[elev_index]; ray->h.fix_angle = vcp_data.fixed_angle[elev_index]; ray->h.vel_res = vcp_data.vel_res; + if (ray_hdr.azm_res != 1) + ray->h.beam_width = 1.0; + else ray->h.beam_width = 0.5; - /* Get some values using message type 1 routines. - * First load VCP and elevation numbers into msg 1 ray. + /* For convenience, use message type 1 routines to get some values. + * First load VCP and elevation numbers into a msg 1 ray. */ m1_ray.vol_cpat = vcp_data.vcp; m1_ray.elev_num = ray_hdr.elev_num; - m1_ray.unam_rng = wsr88d_ray.unamb_rng; - if (ray_hdr.azm_res != 1) - ray->h.beam_width = 1.0; - else ray->h.beam_width = 0.5; + m1_ray.unam_rng = (short) (wsr88d_ray->unamb_rng * 10.); + /* Get values from message type 1 routines. */ ray->h.frequency = wsr88d_get_frequency(&m1_ray); ray->h.pulse_width = wsr88d_get_pulse_width(&m1_ray); ray->h.pulse_count = wsr88d_get_pulse_count(&m1_ray); - ray->h.prf = wsr88d_get_prf(&m1_ray); + ray->h.prf = (int) wsr88d_get_prf(&m1_ray); ray->h.wavelength = 0.1071; } int wsr88d_get_vol_index(char* dataname) { - int vol_index; - - if (strncmp(dataname, "DREF", 4) == 0) vol_index = DZ_INDEX; - if (strncmp(dataname, "DVEL", 4) == 0) vol_index = VR_INDEX; - if (strncmp(dataname, "DSW", 3) == 0) vol_index = SW_INDEX; - /* TODO: Add the other data moments. */ - - return vol_index; + if (strncmp(dataname, "DREF", 4) == 0) return DZ_INDEX; + if (strncmp(dataname, "DVEL", 4) == 0) return VR_INDEX; + if (strncmp(dataname, "DSW", 3) == 0) return SW_INDEX; + if (strncmp(dataname, "DZDR", 4) == 0) return DR_INDEX; + if (strncmp(dataname, "DPHI", 4) == 0) return PH_INDEX; + if (strncmp(dataname, "DRHO", 4) == 0) return RH_INDEX; + + return -1; } +#define MAXRAYS_M31 800 +#define MAXSWEEPS 20 -void wsr88d_load_ray_into_radar(Wsr88d_ray_m31 wsr88d_ray, int isweep, int iray, +void wsr88d_load_ray_into_radar(Wsr88d_ray_m31 *wsr88d_ray, int isweep, Radar *radar) { - Ray *ray; + /* Load data into ray structure for each data field. */ + + int data_index; + int *field_offset; + int ifield, nfields; + int iray; + const nconstblocks = 3; + + Data_moment_hdr data_hdr; + int ngates, do_swap; + int i, hdr_size; + unsigned short item; + float value, scale, offset; + unsigned char *data; Range (*invf)(float x); float (*f)(Range x); + Ray *ray; int vol_index, waveform; - - enum waveforms {surveillance=1, doppler_ambres, doppler_no_ambres, batch}; - -/* for each data moment do - get the name of the data moment - get new volume if needed - get new sweep if needed - get new ray - put this data moment in ray - endfor each data moment -*/ - - /* Note: The data moment type can only be determined by the name within the - * individual data moment block. The name of the pointer is not reliable. - * For example, in legacy resolution mode, dbptr_ref points to the velocity - * data moment in velocity split cuts. Apparently the location of the first - * data moment is always stored in the reflectivity pointer (dbptr_ref), and - * sometimes this is velocity. When this occurs, the velocity data pointer - * (dbptr_vel) then points to spectrum width. - * With super resolution, there actually is reflectivity in the velocity - * split cut. It's there for use with the recombination algorithm. - */ - - if (wsr88d_ray.ray_hdr.dbptr_ref > 0) { - vol_index = wsr88d_get_vol_index(wsr88d_ray.ref->data_hdr.dataname); + char *type_str; + + int keep_hi_prf_dz = 0; /* TODO: implement an interface for this. */ + + enum waveforms {surveillance=1, doppler_w_amb_res, doppler_no_amb_res, + batch}; + + nfields = wsr88d_ray->ray_hdr.data_block_count - nconstblocks; + field_offset = (int *) &wsr88d_ray->ray_hdr.radial_const; + do_swap = little_endian(); + iray = wsr88d_ray->ray_hdr.azm_num - 1; + + for (ifield=0; ifield < nfields; ifield++) { + field_offset++; + data_index = *field_offset; + /* Get data moment header. */ + hdr_size = sizeof(data_hdr); + memcpy(&data_hdr, &wsr88d_ray->data[data_index], hdr_size); + if (do_swap) wsr88d_swap_data_hdr(&data_hdr); + data_index += hdr_size; + + vol_index = wsr88d_get_vol_index(data_hdr.dataname); + if (vol_index < 0) { + fprintf(stderr,"wsr88d_load_ray_into_radar: Unknown dataname %s. " + "isweep = %d, iray = %d.\n", data_hdr.dataname, isweep, + iray); + return; + } switch (vol_index) { - case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break; - case VR_INDEX: f = VR_F; invf = VR_INVF; break; - case SW_INDEX: f = SW_F; invf = SW_INVF; break; - default: f = DZ_F; invf = DZ_INVF; break; + case DZ_INDEX: f = DZ_F; invf = DZ_INVF; + type_str = "Reflectivity"; break; + case VR_INDEX: f = VR_F; invf = VR_INVF; + type_str = "Velocity"; break; + case SW_INDEX: f = SW_F; invf = SW_INVF; + type_str = "Spectrum width"; break; + case DR_INDEX: f = DR_F; invf = DR_INVF; + type_str = "Diff. Reflectivity"; break; + case PH_INDEX: f = PH_F; invf = PH_INVF; + type_str = "Diff. Phase"; break; + case RH_INDEX: f = RH_F; invf = RH_INVF; + type_str = "Correlation Coef (Rho)"; break; } - /* If this is reflectivity, check the waveform type to make sure - * it isn't from a Doppler split cut. - * We only keep reflectivity if the waveform type is surveillance or - * batch, or the elevation is above the split cut elevations. - */ + waveform = vcp_data.waveform[isweep]; - if (vol_index != DZ_INDEX || - (waveform == surveillance || waveform == batch || - vcp_data.fixed_angle[isweep] >= 6.0)) - { - if (radar->v[vol_index] == NULL) { - radar->v[vol_index] = RSL_new_volume(MAXSWEEPS); - radar->v[vol_index]->h.f = f; - radar->v[vol_index]->h.invf = invf; - } - if (radar->v[vol_index]->sweep[isweep] == NULL) { - radar->v[vol_index]->sweep[isweep] = RSL_new_sweep(MAXRAYS_M31); - radar->v[vol_index]->sweep[isweep]->h.f = f; - radar->v[vol_index]->sweep[isweep]->h.invf = invf; - } - ray = RSL_new_ray(wsr88d_ray.ref->data_hdr.ngates); - wsr88d_load_ray_data(wsr88d_ray.ref, ray); - wsr88d_load_ray_hdr(wsr88d_ray, ray); - radar->v[vol_index]->sweep[isweep]->ray[iray] = ray; - radar->v[vol_index]->sweep[isweep]->h.nrays = iray+1; - } - } - if (wsr88d_ray.ray_hdr.dbptr_vel > 0) { - vol_index = wsr88d_get_vol_index(wsr88d_ray.vel->data_hdr.dataname); - switch (vol_index) { - case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break; - case VR_INDEX: f = VR_F; invf = VR_INVF; break; - case SW_INDEX: f = SW_F; invf = SW_INVF; break; - default: f = DZ_F; invf = DZ_INVF; break; - } + /* Ignore short-range reflectivity from velocity split cuts unless + * keep_hi_prf_dz is set. The indicators for this type of + * reflectivity are surveillance mode of 0 and elevation angle + * below 6 degrees. + */ + if (vol_index == DZ_INDEX && (vcp_data.surveil_prf_num[isweep] == 0 && + vcp_data.fixed_angle[isweep] < 6.0 && !keep_hi_prf_dz)) + continue; + + /* Load the data for this field. */ if (radar->v[vol_index] == NULL) { radar->v[vol_index] = RSL_new_volume(MAXSWEEPS); radar->v[vol_index]->h.f = f; radar->v[vol_index]->h.invf = invf; + radar->v[vol_index]->h.type_str = type_str; } if (radar->v[vol_index]->sweep[isweep] == NULL) { radar->v[vol_index]->sweep[isweep] = RSL_new_sweep(MAXRAYS_M31); radar->v[vol_index]->sweep[isweep]->h.f = f; radar->v[vol_index]->sweep[isweep]->h.invf = invf; } - ray = RSL_new_ray(wsr88d_ray.vel->data_hdr.ngates); - wsr88d_load_ray_data(wsr88d_ray.vel, ray); - wsr88d_load_ray_hdr(wsr88d_ray, ray); - radar->v[vol_index]->sweep[isweep]->ray[iray] = ray; - radar->v[vol_index]->sweep[isweep]->h.nrays = iray+1; - } + ngates = data_hdr.ngates; + ray = RSL_new_ray(ngates); - if (wsr88d_ray.ray_hdr.dbptr_sw > 0) { - vol_index = wsr88d_get_vol_index(wsr88d_ray.sw->data_hdr.dataname); - switch (vol_index) { - case DZ_INDEX: f = DZ_F; invf = DZ_INVF; break; - case VR_INDEX: f = VR_F; invf = VR_INVF; break; - case SW_INDEX: f = SW_F; invf = SW_INVF; break; - default: f = DZ_F; invf = DZ_INVF; break; - } - if (radar->v[vol_index] == NULL) { - radar->v[vol_index] = RSL_new_volume(MAXSWEEPS); - radar->v[vol_index]->h.f = f; - radar->v[vol_index]->h.invf = invf; - } - if (radar->v[vol_index]->sweep[isweep] == NULL) { - radar->v[vol_index]->sweep[isweep] = RSL_new_sweep(MAXRAYS_M31); - radar->v[vol_index]->sweep[isweep]->h.f = f; - radar->v[vol_index]->sweep[isweep]->h.invf = invf; + /* Convert data to float, then use range function to store in ray. + * Note: data range is 2-255. 0 means signal is below threshold, and 1 + * means range folded. + */ + + offset = data_hdr.offset; + scale = data_hdr.scale; + if (data_hdr.scale == 0) scale = 1.0; + data = &wsr88d_ray->data[data_index]; + for (i = 0; i < ngates; i++) { + if (data_hdr.datasize_bits != 16) { + item = *data; + data++; + } else { + item = *(unsigned short *)data; + if (do_swap) swap_2_bytes(&item); + data += 2; + } + if (item > 1) + value = (item - offset) / scale; + else value = (item == 0) ? BADVAL : RFVAL; + ray->range[i] = invf(value); + ray->h.f = f; + ray->h.invf = invf; } - ray = RSL_new_ray(wsr88d_ray.sw->data_hdr.ngates); - wsr88d_load_ray_data(wsr88d_ray.sw, ray); wsr88d_load_ray_hdr(wsr88d_ray, ray); + ray->h.range_bin1 = data_hdr.range_first_gate; + ray->h.gate_size = data_hdr.range_samp_interval; + ray->h.nbins = ngates; radar->v[vol_index]->sweep[isweep]->ray[iray] = ray; radar->v[vol_index]->sweep[isweep]->h.nrays = iray+1; - } - + } /* for each data field */ } - -void wsr88d_load_sweep_header(Radar *radar, int isweep, - Wsr88d_ray_m31 wsr88d_ray) +void wsr88d_load_sweep_header(Radar *radar, int isweep) { - int ivolume; - Ray_header_m31 ray_hdr; + int ivolume, nrays; Sweep *sweep; - int vcp; - - ray_hdr = wsr88d_ray.ray_hdr; + Ray *last_ray; for (ivolume=0; ivolume < MAX_RADAR_VOLUMES; ivolume++) { - if (radar->v[ivolume] != NULL && radar->v[ivolume]->sweep[isweep] != NULL) { + if (radar->v[ivolume] != NULL && + radar->v[ivolume]->sweep[isweep] != NULL) { sweep = radar->v[ivolume]->sweep[isweep]; - radar->v[ivolume]->sweep[isweep]->h.sweep_num = ray_hdr.elev_num; - radar->v[ivolume]->sweep[isweep]->h.elev = - vcp_data.fixed_angle[isweep]; - if (ray_hdr.azm_res != 1) - sweep->h.beam_width = 1.0; - else sweep->h.beam_width = 0.5; + nrays = sweep->h.nrays; + if (nrays == 0) continue; + last_ray = sweep->ray[nrays-1]; + sweep->h.sweep_num = last_ray->h.elev_num; + sweep->h.elev = vcp_data.fixed_angle[isweep]; + sweep->h.beam_width = last_ray->h.beam_width; sweep->h.vert_half_bw = sweep->h.beam_width / 2.; sweep->h.horz_half_bw = sweep->h.beam_width / 2.; } @@ -685,50 +517,78 @@ void wsr88d_load_sweep_header(Radar *radar, int isweep, } -Radar *load_wsr88d_m31_into_radar(Wsr88d_file *wf) +Radar *wsr88d_load_m31_into_radar(Wsr88d_file *wf) { Wsr88d_msg_hdr msghdr; Wsr88d_ray_m31 wsr88d_ray; short non31_seg_remainder[1202]; /* Remainder after message header */ - int end_of_vos = 0, isweep = 0, iray = 0; + int end_of_vos = 0, isweep = 0; int msg_hdr_size, msg_size, n; + int prev_elev_num = 1, prev_raynum = 0, raynum = 0; Radar *radar = NULL; + enum radial_status {START_OF_ELEV, INTERMED_RADIAL, END_OF_ELEV, BEGIN_VOS, + END_VOS}; -/* Message type 31 is a variable length message, whereas all other message - * types are made up of 2432 byte segments. To handle this, we read the - * message header and check the message type. If it is not 31, then we read - * the remainder of the constant size segment. If message type is 31, we read - * the remainder of the message by the size given in message header. - * When reading the message header, we must include 12 bytes inserted - * by RPG, which we ignore, followed by the 8 halfwords (short integers) which - * make up the actual message header. - * For more information, see the "Interface Control Document for the RDA/RPG" - * at the WSR-88D Radar Operations Center web site. - */ + + /* Message type 31 is a variable length message. All other types consist of + * 1 or more segments of length 2432 bytes. To handle all types, we read + * the message header and check the type. If not 31, then simply read + * the remainder of the 2432-byte segment. If it is 31, use the size given + * in message header to determine how many bytes to read. + */ n = fread(&msghdr, sizeof(Wsr88d_msg_hdr), 1, wf->fptr); /* printf("msgtype = %d\n", msghdr.msg_type); */ msg_hdr_size = sizeof(Wsr88d_msg_hdr) - sizeof(msghdr.rpg); - radar = RSL_new_radar(MAX_RADAR_VOLUMES); - + while (! end_of_vos) { if (msghdr.msg_type == 31) { if (little_endian()) wsr88d_swap_m31_hdr(&msghdr); - /* Get size in bytes of message following message header. - * The size given in message header is in halfwords, so double it. + /* Get size of the remainder of message. The given size is in + * halfwords; convert it to bytes. */ msg_size = (int) msghdr.msg_size * 2 - msg_hdr_size; n = read_wsr88d_ray_m31(wf, msg_size, &wsr88d_ray); if (n <= 0) return NULL; + raynum = wsr88d_ray.ray_hdr.azm_num; + if (raynum > MAXRAYS_M31) { + fprintf(stderr,"Error: raynum = %d, exceeds MAXRAYS_M31" + " (%d)\n", raynum, MAXRAYS_M31); + fprintf(stderr,"isweep = %d\n", isweep); + RSL_free_radar(radar); + return NULL; + } - /* Load this ray into radar structure ray. */ - wsr88d_load_ray_into_radar(wsr88d_ray, isweep, iray, radar); - iray++; + /* Check for an unexpected start of new elevation, and issue a + * warning if this has occurred. This condition usually means + * less rays then expected in the sweep that just ended. + */ + if (wsr88d_ray.ray_hdr.radial_status == START_OF_ELEV && + wsr88d_ray.ray_hdr.elev_num-1 > isweep) { + fprintf(stderr,"Warning: Radial status is Start-of-Elevation, " + "but End-of-Elevation was not\n" + "issued for elevation number %d. Number of rays = %d" + "\n", prev_elev_num, prev_raynum); + wsr88d_load_sweep_header(radar, isweep); + isweep++; + prev_elev_num = wsr88d_ray.ray_hdr.elev_num - 1; + } + + /* Load ray into radar structure. */ + wsr88d_load_ray_into_radar(&wsr88d_ray, isweep, radar); + prev_raynum = raynum; + + /* Check for end of sweep */ + if (wsr88d_ray.ray_hdr.radial_status == END_OF_ELEV) { + wsr88d_load_sweep_header(radar, isweep); + isweep++; + prev_elev_num = wsr88d_ray.ray_hdr.elev_num; + } } else { /* msg_type not 31 */ n = fread(&non31_seg_remainder, sizeof(non31_seg_remainder), 1, @@ -737,45 +597,38 @@ Radar *load_wsr88d_m31_into_radar(Wsr88d_file *wf) fprintf(stderr,"Warning: load_wsr88d_m31_into_radar: "); if (feof(wf->fptr) != 0) fprintf(stderr, "Unexpected end of file.\n"); - else fprintf(stderr,"Read failed.\n"); - fprintf(stderr,"Current sweep number: %d\n" - "Last ray read: %d\n", isweep+1, iray); - wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); + else + fprintf(stderr,"Read failed.\n"); + fprintf(stderr,"Current sweep index: %d\n" + "Last ray read: %d\n", isweep, prev_raynum); + wsr88d_load_sweep_header(radar, isweep); return radar; } if (msghdr.msg_type == 5) { wsr88d_get_vcp_data(non31_seg_remainder); radar->h.vcp = vcp_data.vcp; - /* printf("VCP = %d\n", vcp_data.vcp); */ } } - /* Check for end of sweep */ - if (wsr88d_ray.ray_hdr.radial_status == END_OF_ELEV) { - wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); - isweep++; - iray = 0; - } - + /* If not at end of volume scan, read next message header. */ if (wsr88d_ray.ray_hdr.radial_status != END_VOS) { n = fread(&msghdr, sizeof(Wsr88d_msg_hdr), 1, wf->fptr); if (n < 1) { fprintf(stderr,"Warning: load_wsr88d_m31_into_radar: "); - if (feof(wf->fptr) != 0) fprintf(stderr, - "Unexpected end of file.\n"); + if (feof(wf->fptr) != 0) + fprintf(stderr,"Unexpected end of file.\n"); else fprintf(stderr,"Failed reading msghdr.\n"); - fprintf(stderr,"Current sweep number: %d\n" - "Last ray read: %d\n", isweep+1, iray); - wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); - return radar; + fprintf(stderr,"Current sweep index: %d\n" + "Last ray read: %d\n", isweep, prev_raynum); + wsr88d_load_sweep_header(radar, isweep); + end_of_vos = 1; } } else { end_of_vos = 1; - wsr88d_load_sweep_header(radar, isweep, wsr88d_ray); + wsr88d_load_sweep_header(radar, isweep); } - if (feof(wf->fptr) != 0) end_of_vos = 1; - } + } /* while not end of vos */ return radar; }