# include # include # include # include int main ( int argc, char *argv[] ); float gauss ( float, float ); int leap ( int *y ); int nmdays ( int *m, int *y ); float ranfloat ( float xlo, float xhi ); int ranint ( int nlo, int nhi ); int ranintw ( int nlo, int nhi, float *w ); void ymdhms_normalize ( int *y, int *m, int *d, int *h, int *mm, int *s ); /******************************************************************************/ int main ( int argc, char *argv[] ) /******************************************************************************/ /* Purpose: MATT_MESSAGE writes 20 random messages to a MATT message file. Discussion: Modified on 15 April 1997: FREQ --> FREQUENCY Modified time calculation, set MSEC to 0 from 100, SSEC to 100 from 10. Modified on 16 April 1997: I made the names, the order and the types of the variables match the declarations in C3I_.ADA and BEM.H. Modified on 22 April 1997: I restored the NONE option to SCAN. I made RANINTW use NLO and NHI. Modified on 23 April 1997: Kyle changed the format of the MATT messages slightly. I am backing out of the NONE option for SCAN. Added sequence field. Fixed RANINTW (stupid C "FOR" loops are deliberately counter intuitive!). Changed ID to run between 1 and number of EOB threats. Note: Matt's MATT program is on sdi6b::/usr/sim/intg/matt/bin/matt and the data file is sdi6b::/usr/sim/intg/matt/data/mattmess.dat Modified on 30 April 1997: Let LINK run only between 1 and 4 for now. Set MLATITUDE and MLONGITUDE to the reference latitude and longitude. Modified: 01 January 2009 Author: John Burkardt */ { int altitude = 0; char c = 0; int day = 0; char *elnot = NULL; float ewerror = 0.0; FILE *fp = NULL; float frequency = 0.0; int heading = 0; int hour = 0; int i = 0; int id = 0; char *iff = NULL; int imess = 0; /* int ipos = 0; */ float latitude = 0.0; int link = 1; struct tm *loctim = NULL; float longitude = 0.0; /* float maltitude = 2000.0; */ float maxaltitude = 30000.0; float mewerror = 5.0; float mfrequency = 100000000.0; float mheading = 0.0; float minaltitude = 0.0; int minute = 0; float mlatitude = 32.7999347 * 3.14159265 / 180.0; float mlongitude = -97.1644956 * 3.14159265 / 180.0; float mnserror = 5.0; int month = 0; float msecond = 0.0; float mspeed = 150.0; int mxmess = 20; float nserror = 0.0; char *report_mode = NULL; char *report_type = NULL; /* float saltitude = 100.0 */; char *scan = NULL; int second = 0; unsigned int seed = 0; int sequence = 0; float sewerror = 2.0; float sfrequency = 10000000.0; float sheading = 90.0; float slatitude = 0.005; float slongitude = 0.005; float snserror = 2.0; int speed = 0; float ssecond = 100.0; float sspeed = 50.0; time_t systim; float w[10]; int year = 0; /* One day, you will be able to specify the number of messages to be generated on the command line: mattmess -n 20 */ while ( --argc > 0 && (*++argv)[0] == '-' ) { c = (*++argv)[0]; while ( c ) switch (c) { case 'n': printf("Nice try, no can do yet!\n"); /* mxmess = atoi(); */ break; default: break; } } /* Say hello */ printf ( "\n" ); printf ( "MATT_MESSAGE\n"); printf ( " C version\n" ); printf ( "\n" ); printf ( " The MATT Message File Program.\n" ); printf ( "\n" ); printf ( " This program writes a set of messages to a file\n" ); printf ( " which are a combination of threat and survivor\n" ); printf ( " reports, of the sort that MATT might receive\n" ); printf ( " from a satellite transmission.\n" ); printf ( "\n"); /* Get some time information. */ systim = time(NULL); loctim = localtime(&systim); day = (*loctim).tm_mday; month = (*loctim).tm_mon+1; year = 1900 + (*loctim).tm_year; hour = (*loctim).tm_hour; minute = (*loctim).tm_min; second = (*loctim).tm_sec; printf("Date: %d / %d / %d\n", day, month, year); printf("Time: %d : %d : %d\n", hour, minute, second); /* Set the random number seed. */ seed = 3600*hour + 60*minute + second; srand(seed); printf("\n"); printf(" Random number seed is %d.\n",seed); for ( i = 0; i <= 9 ; i++ ) { w[i] = 0.0; } /* Open the new message file. */ fp = fopen ( "matt_message.txt", "w" ); if ( fp == 0 ) { printf("\n"); printf("MATT_MESSAGE: Error!\n"); printf(" Could not open the output file.\n"); exit(EXIT_FAILURE); } fprintf(fp,"#MATT Message File\n"); fprintf(fp,"#\n"); fprintf(fp,"# MATT_MESSAGE program last modified on 30 April 1997.\n"); fprintf(fp,"#\n"); fprintf(fp,"# Random number seed is %d.\n",seed); fprintf(fp,"#\n"); fprintf(fp,"#\n"); fprintf(fp,"#MATT Message Format:\n"); fprintf(fp,"#\n"); fprintf(fp,"# Link | (1-26) \n"); fprintf(fp,"# Report_Mode | (REAL/EXERCISE)\n"); fprintf(fp,"# Report_Type | (ELINT/NONELINT/SURVIVOR)\n"); fprintf(fp,"# ELNOT | (NONE/UNKNOWN/SEVEN/EIGHT/ZEE/A)\n"); fprintf(fp,"# IFF | (FRIEND/FOE/UNKNOWN)\n"); fprintf(fp,"# Scan | (SEARCH/ACQUIRE/TRACK/GUIDANCE)\n"); fprintf(fp,"# Hour | (00-23)\n"); fprintf(fp,"# Minute | (00-59)\n"); fprintf(fp,"# Second | (00-59)\n"); fprintf(fp,"# Day | (01-31)\n"); fprintf(fp,"# Month | (01-12)\n"); fprintf(fp,"# Year | (1997)\n"); fprintf(fp,"# ID | EOB code from THREATS.DAT/Survivor ID\n"); fprintf(fp,"# Sequence | Sequence number (0)\n"); fprintf(fp,"# Speed | (knots)\n"); fprintf(fp,"# Heading | (degrees)\n"); fprintf(fp,"# Altitude | (feet)\n"); fprintf(fp,"# Frequency | (hertz)\n"); fprintf(fp,"# EWError | (NM)\n"); fprintf(fp,"# NSError | (NM)\n"); fprintf(fp,"# Latitude | (radians)\n"); fprintf(fp,"# Longitude | (radians)\n"); /* Beginning of loop. */ for ( imess = 1; imess <= mxmess; imess++ ) { /* Assemble the record by setting the report items to random values. */ altitude = (int) ranfloat(minaltitude,maxaltitude); i=ranint(1,6); if ( i == 1 ) { elnot = "NONE"; } else if ( i == 2 ) { elnot = "UNKNOWN"; } else if ( i == 3 ) { elnot = "SEVEN"; } else if ( i == 4 ) { elnot = "EIGHT"; } else if ( i == 5 ) { elnot = "ZEE"; } else { elnot = "A"; } ewerror = gauss(mewerror,sewerror); frequency = gauss(mfrequency, sfrequency); heading = (int) gauss(mheading,sheading); if ( heading < -180 ) { heading = -180; } else if ( heading > 180 ) { heading = 180; } /* Right now, there are 50 ID numbers in THREATS.DAT. So ID should be between 1 and 50, assuming this is a threat record. Of course, we should really check that we don't repeatedly use the same ID number, as well. */ id = ranint(1,50); i=ranint(1,3); if ( i == 1 ) { iff = "FRIEND"; } else if ( i == 2 ) { iff = "FOE"; } else { iff = "UNKNOWN"; } latitude = gauss(mlatitude,slatitude); /* For now, let LINK run only between 1 and 4. link = ranint(1,26); */ link = ranint(1,4); longitude = gauss(mlongitude,slongitude); nserror = gauss(mnserror,snserror); w[0] = 80.0; w[1] = 20.0; i = ranintw(1,2,w); if ( i == 1 ) { report_mode = "REAL"; } else { report_mode = "EXERCISE"; } w[0] = 70.0; w[1] = 15.0; w[2] = 15.0; i = ranintw(1,3,w); if ( i == 1 ) { report_type = "ELINT"; } else if ( i == 2 ) { report_type = "NONELINT"; } else { report_type = "Survivor"; } i = ranint(1,4); if ( i == 1 ) { scan = "SEARCH"; } else if ( i == 2 ) { scan = "ACQUIRE"; } else if ( i == 3 ) { scan = "TRACK"; } else { scan = "GUIDANCE"; } sequence = 0; speed = abs ( (int) gauss(mspeed,sspeed) ); /* Reset the time. second = second + abs ( (int) gauss(msecond,ssecond) ); to force ISEC to never decrease. */ second = second + (int) gauss(msecond,ssecond); ymdhms_normalize ( &year, &month, &day, &hour, &minute, &second ); /* Write the record to the file. */ fprintf(fp,"#\n"); fprintf(fp,"#MATT Message Number %d\n",imess); fprintf(fp,"#\n"); fprintf(fp," Link | %d\n",link); fprintf(fp," Report_Mode | %s\n",report_mode); fprintf(fp," Report_Type | %s\n",report_type); fprintf(fp," ELNOT | %s\n",elnot); fprintf(fp," IFF | %s\n",iff); fprintf(fp," Scan | %s\n",scan); fprintf(fp," Hour | %d\n",hour); fprintf(fp," Minute | %d\n",minute); fprintf(fp," Second | %d\n",second); fprintf(fp," Day | %d\n",day); fprintf(fp," Month | %d\n",month); fprintf(fp," Year | %d\n",year); fprintf(fp," ID | %d\n",id); fprintf(fp," Sequence | %d\n",sequence); fprintf(fp," Speed (knots) | %d\n",speed); fprintf(fp," Heading (degrees) | %d\n",heading); fprintf(fp," Altitude (FT) | %d\n",altitude); fprintf(fp," Frequency (Hz) | %f\n",frequency); fprintf(fp," EWError (NM) | %f\n",ewerror); fprintf(fp," NSError (NM) | %f\n",nserror); fprintf(fp," Latitude (radians) | %f\n",latitude); fprintf(fp," Longitude (radians) | %f\n",longitude); } /* Close the file. */ fclose ( fp ); printf ( "\n"); printf ( " Wrote %d MATT messages.\n", imess-1 ); /* Terminate. */ printf ( "\n"); printf ( "MATT_MESSAGE:\n"); printf ( " Normal end of execution.\n"); return 0; } /******************************************************************************/ float gauss ( float gmean, float sdev ) /******************************************************************************/ /* Purpose: GAUSS generates an approximately normal random deviate. Discussion: The deviate will have mean GMEAN and standard deviation SDEV. The algorithm used involves adding 12 numbers which are approximately uniformly distributed in [0,1]. Modified: 01 January 2009 Author: John Burkardt Parameters: Input, float GMEAN, the mean of the distribution. Input, float SDEV, the standard deviation of the distribution. An input value of SDEV=0 means GAUSS is guaranteed to return a value of GMEAN. Values of SDEV of larger magnitude mean that GAUSS is likely to return about 68% of its values between GMEAN-SDEV and GMEAN+SDEV, with other values more widely scattered. Because of the approximate nature of this routine, the output value GAUSS will never be less than GMEAN-6*SDEV nor more than GMEAN+6*SDEV. Output, float GAUSS, an approximately random gaussian variable. */ { # define NRAND 12 int i; float temp; float x; x = 0.0; for ( i=1; i <= NRAND; i++ ) { x = x + ( (float) rand() ) / ( (float) RAND_MAX ); } temp = gmean + ( x - 0.5*NRAND ) * sdev; return temp; # undef NRAND } /******************************************************************************/ int leap ( int *y ) /******************************************************************************/ /* Purpose: LEAP determines if a year was a leap year. Modified: 01 January 2009 Author: John Burkardt Parameters: Input, int *Y, the year. Output, int LEAP: 0, the year is NOT a leap year. 1, the year is a leap year. */ { if ( *y%400 == 0 ) { return 1; } else if ( *y%100 == 0 ) { return 0; } else if ( *y%4 == 0 ) { return 1; } else { return 0; } } /******************************************************************************/ int nmdays ( int *m, int *y ) /******************************************************************************/ /* Purpose: NMDAYS returns the number of days in a month. Modified: 01 January 2009 Author: John Burkardt Parameters: Input, int *M, *Y, the month and year. Output, int NMDAYS, the number of days in the given month. */ { int mn; mn = *m % 12; if ( mn == 1 || mn == 3 || mn == 5 || mn == 7 || mn == 8 || mn == 10 || mn == 12 ) { return 31; } else if ( mn == 4 || mn == 6 || mn == 9 || mn == 11 ) { return 30; } else if ( mn == 2 && leap(y) == 1 ) { return 29; } else { return 28; } } /******************************************************************************/ float ranfloat ( float xlo, float xhi ) /******************************************************************************/ /* Purpose: RANFLOAT returns a uniformly random float between XLO and XHI. Modified: 01 January 2009 Author: John Burkardt Parameters: Input, float XLO, XHI, the minimum and maximum acceptable values. Output, int RANFLOAT, a randomly chosen float between XLO and XHI. */ { int temp; float test; test = ( (float) rand() ) / ( (float) RAND_MAX ); temp = (1.0-test)*xlo + test*xhi ; return temp; } /******************************************************************************/ int ranint ( int nlo, int nhi ) /******************************************************************************/ /* Purpose: RANINT returns a uniformly random int NLO and NHI. Modified: 01 January 2009 Author: John Burkardt Parameters: Input, int NLO, NHI, the minimum and maximum acceptable values. Output, int RANINT, the randomly chosen integer. */ { int temp; float test; test = ( (float) rand() ) / ( (float) RAND_MAX ); /* (NHI-NLO+1) is used here safely. Unless TEST=1, the expression TEST*(NHI-NHL+1) will truncate to a number between 0 and NHI-NLO. JVB, 22 April 1997 */ temp = nlo + test * (nhi-nlo+1) ; if ( temp > nhi ) { temp = nhi; } return temp; } /******************************************************************************/ int ranintw ( int nlo, int nhi, float *w ) /******************************************************************************/ /* Purpose: RANINTW returns a random integer with weighted distribution. Discussion: The value returned will be an integer between NLO and NHI, chosen randomly, but with weights given in W. An error occurs if any of the weights are negative, or all of the weights are 0. Modified: 01 January 2009 Author: John Burkardt Parameters: Input, integer NLO, NHI, the lowest and highest values to pick from. Input, float W(NHI+1-NLO), the weights for the various choices. The values in W should all be nonnegative, and at least one value must actually be positive. The values do not have to add up to 1; RANINTW will normalize them itself. Output, int RANINTW, the chosen number, between NLO and NHI. */ { int i; float test; float wpart; float wtot; /* Compute the total of the weights. */ wtot = 0.0; for ( i = nlo ; i <= nhi ; i++) { wtot = wtot + *(w+i-nlo); if ( *(w+i-nlo) < 0.0 ) { printf("\n"); printf("RANINTW: Fatal error!\n"); printf(" Negative weight W(I)=%f.\n",*(w+i-nlo)); exit(EXIT_FAILURE); } } if ( wtot <= 0.0 ) { printf("\n"); printf("RANINTW: Fatal error!\n"); printf(" Nonpositive weight sum is %f.\n",wtot); exit(EXIT_FAILURE); } /* Get a random value, and find the "bin" into which it goes. */ test = ( (float) rand() ) / ( (float) RAND_MAX ); wpart = 0.0; for ( i = nlo; i <= nhi; i++ ) { wpart = wpart + *(w+i-nlo); if ( test*wtot <= wpart ) { return i; } } return nhi; } /******************************************************************************/ void ymdhms_normalize ( int *y, int *m, int *d, int *h, int *mm, int *s ) /******************************************************************************/ /* Purpose: YMDHMS_NORMALIZE normalizes a date. Discussion: The data is presumed to have the form Year/Month/Day/Hour/Minute/Second where, for instance, on input, the value of seconds might be more than 59. Modified: 01 January 2009 Author: John Burkardt Parameters: Input/output, int *Y, *M, *D, *H, *MM, *S, the year, month, day, hour, minutes and seconds of a date. */ { /* 0 <= S < 60. */ while ( *s < 0 ) { *s = *s + 60; *mm = *mm - 1; } while ( *s >= 60 ) { *s = *s - 60; *mm = *mm + 1; } /* 0 <= MM < 60 */ while ( *mm < 0 ) { *mm = *mm + 60; *h = *h - 1; } while ( *mm >= 60 ) { *mm = *mm - 60; *h = *h + 1; } /* 0 <= H < 24 */ while ( *h < 0 ) { *h = *h + 24; *d = *d - 1; } while ( *h >= 24 ) { *h = *h - 24; *d = *d + 1; } /* 1 <= D <= NMDAYS(M,Y) */ while ( *d < 1 ) { *m = *m - 1; *d = *d + nmdays(m,y); } while ( *d > nmdays(m,y) ) { *d = *d - nmdays(m,y); *m = *m + 1; } /* 1 <= M <= 12 */ while ( *m < 1 ) { *m = *m + 12; *y = *y - 1; } while ( *m > 12 ) { *m = *m - 12; *y = *y + 1; } }