/* NASA/TRMM, Code 910.1. This is the TRMM Office Radar Software Library. Copyright (C) 1998 John H. Merritt Space Applications Corporation Vienna, Virginia 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 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 Library General Public License for more details. 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ %{ #define USE_RSL_VARS #include "rapic_routines.h" #include "rsl.h" #include #include #include int rapicerror(char *s); int rapicwrap(char *s); int rapicwrap(char *s); int yywrap(char *s); int rapiclex(void); int nsweep = 0; float angres; Radar *radar, *rapic_radar = NULL; Volume *volume; Sweep *sweep; Ray *ray; /* Rapic format declarations. */ Rapic_sweep_header rh; Rapic_sweep *rs; unsigned char outbuf[2000000]; int outbytes; float azim, elev; float save_elev; int delta_time; int nray = 0; int ifield; int ivolume, isweep, iray; int station_id; int sweepcount[5]; extern int radar_verbose_flag; float rapic_nyquist; %} /* 2/18/98 - John Merritt * * This grammar parses the NT Rapic radar format. The grammar * is not minimal, however, it is self documenting; it closely matches * the brief documentation. */ /*----------------------------------------------------------------- * NT Rapic Volume Structure: * NOTE: '*' marked tokens are preent only in versions > 10.0 * * ImageHeader: * The header contains a set of tokens followed by data. * Each token is seperated by '\n' and all the data is * in ascii. * ScanHeader: * Scan header has the scan details like fieldname, * date/time azimuth,elevation etc. * The different sets of Tokens together with the data * are seperate by '\0'. * ScanData: * This represents the field data in runlehgth code. * Each Ray data contains azimuth,elevation,delta time * since start of this scan and the actual data. * * Here is a brief explanation of each of the Tokens. * * * ImageHeader: * * 1 /IMAGE: * 4 digit number * 10 digit number * * 2 /IMAGESCANS: * Number of scans in this volume * * 3 /IMAGESIZE: * Size of image in bytes * * 4 /SCAN * 1 - * seqnum as given in /IMAGE: * yymoddhhmm * Don't care ( I don't know ) * Target Elevation in degrees. * 0-4 * 0 Reflectivity ?? Index? haven't seen this yet. ?? * 1 Velocity Confirmed this index. * 2 Width Confirmed. * 3 ZDR ?? Index? haven't seen this yet. ?? * 4 Uncorrected Reflectivity. Confirmed. * Don't care * Offset to start of scan header * Size of this scan * add offset to size to get to the next scan * /SCAN is repeated for each scan in the volume. * NOTE: * Unlike other formats each scan need not represent a seperate * elevation. * * 5 /IMAGEHEADER END: * Indicates the end of Image header. * * ScanHeader: * * COUNTRY: * is a country code number * * NAME: * 8 char long station name * * STNID: * A unique number indexing into station details * * LATITUDE: * * Latitude in degrees * * LONGITUDE: * * Longitude in degrees * * HEIGHT: * * Radar height in meters * * DATE: * year = datno % 100 * if year > 80 year += 1900 * else year += 2000 * doy = datno / 100 * Get the julian Number from year,1,1 and add doy -1 * Use Julian date conversion to get calendar date. * NOTE: As simple as remembering your partner's DOB. * * TIME: * Hour and minute * * TIMESTAMP: * * year,month,day,hour,min,sec * * VERS: * 10.01 * * FREQUENCY: * * Radar Frequency. * * PRF: * Pulse repetition Frequency * * PULSELENGTH: * * Pulse length * * RNGRES: * Range between gates * * ANGRES: * BeamWidth in degrees. * * CLEARAIR: ON or OFF * * VIDRES: * Video Resolution can be * 16 OR 256. * * STARTRNG: * Range to First gate in meters. * * ENDRNG: * Maximum range. * * PRODUCT: <[id]> * Ascii text * VOLUMETRIC * NORMAL * * <[id]> * * PASS: of * Number of this scan * Max scan no. * * IMGFMT: * PPI,RHI etc. * * ELEV: * Elevation in degrees * * VIDEO: * Field Name Vel,Refl,Vel,UnCorRefl,Zdr,Wid * * VELLVL: * Velocity Level * * NYQUIST: * Nyquist Velocity * * UNFOLDING: * * None or x:y * * * @ * * AAA.A,EEE.E,TTT=LEN16D1D1D1NLD1D1D1NLNL * * AAA.A Azimuth in degrees * EEE.E Elevation in degress * TTT Delta time in seconds since the start of this scan * LEN16 2 byte long length of radial * * D1 Run length coded Data. * NL Null The Next Byte is count of NULL data. * NLNL End of this Radial * * eg. There will be no white space in the actual radial data. * * @066.1,010.6,004=002082B2817F8C84830048D72D0038 * 999C0036202D35FD2C00238A99008AFE920000 * Azimuth = 66.1 * Elev = 10.6 * Dt = 4 sec since the start * 0020 = Bytes to follow * Data = 82,B2,81,7F,8C,84,83 * 0048 = 48H null bytes * Data = D7,2D * 0038 = 38H null bytes * Data = 99,9C * 0036 = 36H Null bytes * ........................ * 0000 = End of Data. * In versions before 10.1 * @ * AAALEN16D1D1D1NLD1D1D1NLNL * * AAA Azimuth in degrees * LEN16 2 byte long length of radial * * D1 Run length coded Data. * NL Null The Next Byte is count of NULL data. * NLNL End of this Radial * * eg. There will be no white space in the actual radial data. * * @066002082B2817F8C84830048D72D0038 * 999C0036202D35FD2C00238A99008AFE920000 * Azimuth = 66 * 0020 = Bytes to follow * Data = 82,B2,81,7F,8C,84,83 * 0048 = 48H null bytes * Data = D7,2D * 0038 = 38H null bytes * Data = 99,9C * 0036 = 36H Null bytes * ........................ * 0000 = End of Data. * * Please see the attached sample.vol to give a overall picture of the data. * This is the dump of the volume with white space inserted to make it readable. * Radial data dump is in hex. */ %token IMAGE IMAGESCANS IMAGESIZE IMAGEEND %token SCAN IMAGEHEADEREND %token NUMBER %token ALPHA %token FLOATNUMBER %token BRACKETNUM %token COUNTRY %token NAME %token STNID %token LATITUDE %token LONGITUDE %token HEIGHT %token DATE %token TIME %token TIMESTAMP %token VERS %token FREQUENCY %token PRF %token PULSELENGTH %token RNGRES %token ANGRES %token ANGLERATE %token CLEARAIR ON OFF %token VIDRES %token STARTRNG %token ENDRNG %token PRODUCT %token PASS %token IMGFMT %token ELEV %token VIDEO %token VELLVL %token NYQUIST %token UNFOLDING %token AT %token VOLUMETRIC %token NORMAL %token OF %token REFL VEL UNCORREFL ZDR WID %token NONE %token RAYDATA %token ENDRADARIMAGE %union { Charlen token; } %expect 61 %% rapic_recognized : complete_header sweeps imageend { if (radar_verbose_flag) fprintf(stderr, "SUCCESSFUL parse\n"); sprintf(radar->h.name, "%s", rh.namestr); sprintf(radar->h.radar_name, "%s", rh.namestr); radar = fill_header(radar); radar = RSL_prune_radar(radar); rapic_radar = radar; YYACCEPT; } sweeps : sweep | sweeps sweep sweep : sweepheader rays ENDRADARIMAGE { /* Attach the sweep to the volume. */ if (radar_verbose_flag) fprintf(stderr, "Attach the sweep %d to the volume %d.\n", isweep, ivolume); radar->v[ivolume]->sweep[isweep] = sweep; radar->v[ivolume]->h.f = sweep->h.f; radar->v[ivolume]->h.invf = sweep->h.invf; } sweepheader : scanheader { /* float c = RSL_SPEED_OF_LIGHT; */ if (rh.angle_resolution != 0) sweep = RSL_new_sweep((int)(360.0/rh.angle_resolution+0.5)); if (fabs(rh.elev - save_elev) > .5) { /* New sweep elevation. */ isweep++; save_elev = rh.elev; } nray = 0; /* rapic_nyquist = c*((float)rh.prf/10.)/(4.*(float)rh.freq*100000.0); */ } imageend : IMAGEEND seqno imgno complete_header : imageheader IMAGEHEADEREND { if (radar_verbose_flag) fprintf(stderr, "sweepcount[0] = %d\n", sweepcount[0]); if (sweepcount[0] > 0) { radar->v[DZ_INDEX] = RSL_new_volume(sweepcount[0]); radar->v[DZ_INDEX]->h.type_str = strdup("Reflectivity"); } if (radar_verbose_flag) fprintf(stderr, "sweepcount[1] = %d\n", sweepcount[1]); if (sweepcount[1] > 0) { volume = radar->v[VR_INDEX] = RSL_new_volume(sweepcount[1]); volume->h.type_str = strdup("Velocity"); volume->h.calibr_const = 0.0; } if (radar_verbose_flag) fprintf(stderr, "sweepcount[2] = %d\n", sweepcount[2]); if (sweepcount[2] > 0) { radar->v[SW_INDEX] = RSL_new_volume(sweepcount[2]); volume->h.type_str = strdup("Spectral Width"); volume->h.calibr_const = 0.0; } if (radar_verbose_flag) fprintf(stderr, "sweepcount[3] = %d\n", sweepcount[3]); if (sweepcount[3] > 0) { radar->v[ZD_INDEX] = RSL_new_volume(sweepcount[3]); volume->h.type_str = strdup("Reflectivity Depolarization Ratio"); volume->h.calibr_const = 0.0; } if (radar_verbose_flag) fprintf(stderr, "sweepcount[4] = %d\n", sweepcount[4]); if (sweepcount[4] > 0) { radar->v[ZT_INDEX] = RSL_new_volume(sweepcount[4]); volume->h.type_str = strdup("Total Reflectivity"); volume->h.calibr_const = 0.0; } isweep = -1; /* It keeps track of the sweep number across all field * types; volumes. It is immediately bumped to 0 when * the sweepheader is parsed. */ save_elev = 99999; } ; imageheader : imageheader_item | imageheader imageheader_item | /* Empty */ ; imageheader_item : IMAGE seqno imgno { radar = RSL_new_radar(MAX_RADAR_VOLUMES); sweepcount[0] = 0; sweepcount[1] = 0; sweepcount[2] = 0; sweepcount[3] = 0; sweepcount[4] = 0; radar->h.number = atoi($2); } | IMAGESCANS number | IMAGESIZE number { if (atoi($2) <= 0) { fprintf(stderr, "RAPIC: /IMAGESIZE == %d. RAPIC ingest returning NULL.\n", atoi($2)); YYERROR; } } | scanlist ; scanlist : SCAN scanno ':' seqno datetime dc elev fieldno dc offset size { ifield = atoi($8); sweepcount[ifield]++; } /* * Now, describe some scan header fields. */ rays : ray | rays ray | /* EMPTY */ ; ray : RAYDATA { /* fprintf(stderr, "YACC len=%d text=<", yylval.token.len); */ /* binprint(yylval.token.s, yylval.token.len); */ /* fprintf(stderr, ">\n"); */ /* Quiet the compilier, because I only use the rsl_f_list and rsl_invf_list. */ RSL_ftype[0] = RSL_ftype[0]; /* Use yylval.token.s and yylval.token.len */ memset(outbuf, '\0', sizeof(outbuf)); rapic_decode((unsigned char *)yylval.token.s, yylval.token.len, outbuf, &outbytes, &azim, &elev, &delta_time); /* fprintf(stderr, "RAYDATA: ray %d, ivol %d, isweep %d, azim %f, elev %f, dtime %d, size=%d\n", nray, ivolume, isweep, azim, elev, delta_time, outbytes); */ ray = RSL_new_ray(outbytes); rapic_load_ray_header(rh, nray, isweep, elev, azim, &ray->h); /* Mostly from the scanheader (rh). */ ray->h.azimuth = azim; /* if (39h.elev = elev; ray->h.sec += delta_time; ray->h.f = RSL_f_list[ivolume]; /* Data conversion function. f(x). */ ray->h.invf = RSL_invf_list[ivolume]; /* invf(x). */ rapic_fix_time(ray); rapic_load_ray_data(outbuf, outbytes, ivolume, ray); #define DODO #undef DODO #ifdef DODO if (ray->h.ray_num == 0 && ivolume == 1 && isweep == 0) { int i; fprintf(stderr, "RAYDATA: ray %d, ivol %d, isweep %d, azim %f, elev %f, dtime %d, size=%d\n", nray, ivolume, isweep, azim, elev, delta_time, outbytes); for (i=0; ih.nbins; i++) { fprintf(stderr,"YACCray->range[%d] = %d %f\n", i, (int)ray->range[i], ray->h.f(ray->range[i])); } } #endif /* Attach the ray to the sweep. */ sweep->ray[nray] = ray; sweep->h.beam_width = ray->h.beam_width; sweep->h.vert_half_bw = sweep->h.beam_width / 2.0; sweep->h.horz_half_bw = sweep->h.beam_width / 2.0; sweep->h.sweep_num = isweep; sweep->h.elev = ray->h.elev; sweep->h.f = ray->h.f; sweep->h.invf = ray->h.invf; nray++; /* } */ } scanheader : scanheaditem | scanheader scanheaditem | /* EMPTY */ ; /* Each of these items are the header for a sweep. */ scanheaditem : NAME namestr { memmove(rh.namestr,$2,$2); } | COUNTRY code { rh.country = atoi($2); } | STNID idno { rh.station_id_no = atoi($2); } | LATITUDE lat { rh.lat = atof($2); } | LONGITUDE lon { rh.lon = atof($2); } | HEIGHT alt { rh.height = atof($2); } | DATE datno { rh.datno = atoi($2); } | TIME hhmm { rh.hhmm = atof($2); } | TIMESTAMP yyyymoddhhmmss { memmove(rh.yyyymoddhhmmss,$2,$2); } | VERS versionNumber { rh.versionNumber = atof($2); } | FREQUENCY freq { rh.freq = atoi($2); } | PRF prf { rh.prf = atoi($2); } | PULSELENGTH len { rh.pulselen = atof($2); } | RNGRES gatewidth { rh.range_resolution = atoi($2); } | ANGLERATE anglerate { rh.anglerate = atof($2); } | CLEARAIR clearair { memmove(rh.clearair,$2,$2);} | ANGRES angle { rh.angle_resolution = atof($2); } | VIDRES res { rh.video_resolution = atoi($2); } | STARTRNG rng { rh.start_range = atoi($2); } | ENDRNG rng { rh.end_range = atoi($2); } | PRODUCT typeid BRACKETNUM { memmove(rh.product_type,$2,$2); } | PRODUCT | PASS noofnscans | ELEV elev { rh.elev = atof($2); } | VELLVL level { rh.vellvl = atof($2); } | NYQUIST nyq { rh.nyquist = atof($2); rapic_nyquist = rh.nyquist; } | VIDEO field { memmove(rh.video,$2,$2); } | IMGFMT type { memmove(rh.imgfmt,$2,$2); } | UNFOLDING ratio /* Already loaded: rh.ratio1, rh.ratio2 */ ; real : number | FLOATNUMBER number : NUMBER seqno : number scanno : number imgno : number datetime : number dc : real | ALPHA elev : real fieldno : number offset : number size : number datno : number code : number namestr : ALPHA idno : number lat : real lon : real alt : real hhmm : real yyyymoddhhmmss : number versionNumber : real freq : number prf : number len : real gatewidth : number angle : real anglerate : real clearair : ON | OFF res : number rng : number typeid : VOLUMETRIC | NORMAL noofnscans : no OF nscans no : number {rh.scannum = atoi($1);} nscans : number {rh.ofscans = atoi($1);} type : ALPHA field : REFL {ivolume = DZ_INDEX; volume = radar->v[ivolume];} | VEL {ivolume = VR_INDEX; volume = radar->v[ivolume];} | UNCORREFL {ivolume = ZT_INDEX; volume = radar->v[ivolume];} | ZDR {ivolume = ZD_INDEX; volume = radar->v[ivolume];} | WID {ivolume = SW_INDEX; volume = radar->v[ivolume];} level : real nyq : real ratio : NONE {rh.ratio1 = 0; rh.ratio2 = 0;} | number ':' number {rh.ratio1 = atoi($1); rh.ratio2 = atoi($3);} %% int rapicerror(char *s) { fprintf(stderr, "RAPIC ERROR: <%s> on token <", s); binprint(yylval.token.s, yylval.token.len); fprintf(stderr, ">\n"); return 1; } int rapicwrap(char *s) { yywrap(s); return 1; }