#include #include #include /* TO DO OPTICAL BACKTRACKING IN FEET, DEFINE ALTUNITS AS 'F' */ /* TO DO OPTICAL BACKTRACKING IN METERS, DEFINE ALTUNITS AS 'M' */ /* SET TURBODOS TO 1 IF COMPILIUNG IN DOS TURBO C */ #define TURBODOS 0 /* ** SET ALTSW TO 'M' FOR METERS ** */ #define ALTUNITS 'F' /* ** SET INUNITS TO 'M' FOR CM/GR, 'E' FOR IN/OZ ** */ #define INUNITS 'E' /* ** SET TEMPSW TO C OR F ** */ #define TEMPSW 'F' /* ** OUNCES TO GRAMS ** */ #define OZTOG 28.35 /* ** INCHES TO METERS ** */ #define INCHTOM .0254 #if (TURBODOS == 1) /* DEFINE SCREEN CLEAR FUNCTION */ #include #define CLS clrscr() #define printf cprintf #else #define CLS printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n") #endif /* number of repetitions */ #define NUMREP 100 /* ** PROGRAM backtrak.c Version 3.0 - WITH ENGINE STATS - ** */ /* ** TRAJECTORY STATS, Cd FROM ASCENT TIME OR ALTITUDE ** */ /* ** OR STRAIGHT SIMULATION FROM Cd ** */ /* ** LARRY CURCIO ** */ /* ** COPYRIGHT APRIL 1993 ** */ /* ** FREE NOT-FOR-PROFIT DISTRIBUTION ** */ /* ** USES FEHSKENS MALEWICKI APPROXIMATIONS ** */ /* Relatively naive C version by Paul Campbell MAY 1993 */ /* Subsequent updates to C code By Larry Curcio */ /* Version 1.1 contains NAR stats for all certified engines as of May 1993 */ /* Also altitude can be specified in meters or feet by #define */ /* Version 1.2 allows input of Cd for direct RASP. */ /* Version 2.0: optimal mass, average velocity, and screen clearing */ /* Version 2.1 has temperature and EE15/AE15, D21, and E25 engines */ /* Note ESTES E15 is now EE15 and AEROTECH E15 is now AE15 */ /* Also temperature may be set in F or C by #define */ /* Version 3.0 has English units for input */ /* Also has conversion between UNIX and TURBO DOS by TURBODOS switch */ /* Has color/screen clearing for TURBO DOS */ /* SUBSTITUTE YOUR SYSTEMS'S SCREEN CLEARING PROCEDURE FOR #define CLS */ struct motor { char name[20]; float impulse; float mp; float tb; }; struct motor motors[] = { /* name impulse mass burn time */ /* ** PARAMETERS (FROM NAR CERIFICATION RECORDS): ** */ /* ** NAME, IMPULSE, PROP. MASS, BURN TIME ** */ /* ** ADD YOUR OWN ** */ /* ** ESTES ENGINES ** */ { "1/4A3",0.61,1.2,.24 }, { "1/2A3-T",1.15,2.0,.44 }, { "A3-T",2.09,3.3,.73 }, { "A10-T",2.03,3.8,1.13 }, { "1/2A6",1.14,2.6,0.32 }, { "B14",4.37,5.3,0.23 }, { "D11-P",17.49,24.5,1.86 }, { "A8",2.30,3.3,.45 }, /***** ADD AND SUBTRACT 1 OR 2 Z-SCORES ****** */ { "A8+1Z",2.42,3.3,.45 }, { "A8+2Z",2.54,3.3,.45 }, { "A8-1Z",2.18,3.3,.45 }, { "A8-2Z",2.06,3.3,.45 }, { "B4",4.35,6.0,1.00 }, { "B4+1Z",4.49,6.0,1.00 }, { "B4-1Z",4.21,6.0,1.00 }, { "B4+2Z",4.63,6.0,1.00 }, { "B4-2Z",4.07,6.0,1.00 }, { "B6",4.42,5.6,.75 }, { "B6+1Z",4.70,5.6,.75 }, { "B6+2Z",4.98,5.6,.75 }, { "B6-1Z",4.14,5.6,.75 }, { "B6-2Z",3.86,5.6,.75 }, { "B8",4.35,5.5,.54 }, { "B8+1Z",4.54,5.5,.54 }, { "B8+2Z",4.73,5.5,.54 }, { "B8-1Z",4.16,5.5,.54 }, { "B8-2Z",3.97,5.5,.54 }, { "C5",9.03,11.3,1.58 }, { "C5+1Z",9.63,11.3,1.58 }, { "C5+2Z",10.23,11.3,1.58 }, { "C5-1Z",8.43,11.3,1.58 }, { "C5-2Z",7.83,11.3,1.58 }, { "C6",8.52,10.8,1.45 }, { "C6+1Z",8.79,10.8,1.45 }, { "C6+2Z",9.06,10.8,1.45 }, { "C6-1Z",8.25,10.8,1.45 }, { "C6-2Z",7.98,10.8,1.45 }, { "D12", 15.80,21.1,1.55 }, { "D12+1Z",16.20,21.1,1.55 }, { "D12+2Z",16.60,21.1,1.55 }, { "D12-1Z",15.40,21.1,1.55 }, { "D12-2Z",15.00,21.1,1.55 }, /* ** D12 CLUSTERS ** */ { "2D12",31.60,42.2,1.55 }, { "3D12",47.40,63.3,1.55 }, { "4D12",63.20,84.4,1.55 }, { "D11",12.63,17.5,1.27 }, { "D11+1Z",12.99,17.5,1.27 }, { "D11+2Z",13.35,17.5,1.27 }, { "D11-1Z",12.27,17.5,1.27 }, { "D11-2Z",11.91,17.5,1.27 }, /* **** ESTES E15 CALLED EE15 TO DISTINGUISH FROM AEROTECH **** */ {"EE15",29.5,39.4,2.63}, {"EE15+1Z",30.25,39.4,2.63}, {"EE15+2Z",31.0,39.4,2.63}, {"EE15-1Z",28.75,39.4,2.63}, {"EE15-2Z",28.0,39.4,2.63}, /* ** MRC ENGINES ** */ { "MRCA8", 2.30, 3.0,.42 }, { "MRCB4", 4.73, 6.0, 1.19 }, { "MRCB6", 3.6, 6.0, .81 }, { "MRCC6", 8.25, 12.0, 1.89 }, /* ** AEROTECH ENGINES ** */ { "D7", 19.93, 11, 3.12 }, { "D8", 18.84, 9.5, 2.42 }, { "D21", 18.67, 9.6, 0.96}, { "E6", 37.55, 21.5, 7.45 }, { "E10", 39.8, 21, 4.06 }, /* **** AEROTECH E15 CALLED AE15 TO DISTINGUISH FROM ESTES ** */ { "AE15", 38.38, 17.8, 2.72}, { "E25", 20.56, 11.0, 0.99}, { "E28", 38.14, 18.9, 1.4 }, { "E30", 39.13, 19.2, 1.25 }, { "E50", 37.35, 18.9, 0.76 }, { "E45", 38.45, 19.2, 0.77 }, { "F9", 49.76, 24.5, 5.05 }, { "F30", 56.87, 28.3, 2.00 }, { "F44", 79.80, 37.7, 1.80 }, { "F15", 75.96, 37.7, 5.33 }, { "F10", 75.96, 40.7, 7.34 }, { "F20", 74.88, 37.7, 4.07 }, { "F80", 75.34, 37.7, 0.97 }, { "F41", 79.57, 37.7, 1.80 }, { "F25", 79.57, 35.6, 3.40 }, { "F60", 78.05, 37.9, 1.62 }, { "G25", 119.05, 62.5, 4.86 }, { "G40", 114.10, 55.1, 3.03 }, { "G80", 115.99, 56.9, 1.42 }, /* ** QUEST ENGINES ** */ { "QC6",8.10,11.0,1.71 }, { "QA6",2.12,3.5,0.41 }, { "QB6",4.63,6.5,0.75 }, /* ** FSI MOTORS ** */ { "FSIA6",1.83,30,0.29 }, { "FSIB6",4.35,6.0,0.56 }, { "FSIC6",8.55,12.0,1.40 }, { "FSID18",14.0,16.1,0.75 }, { "FSID20",15.29,20.0,0.81 }, { "FSIE5",20.65,21.0,5.49 }, { "FSIE60",27.6,40.0,0.85 }, { "FSIF7",48.8,58.0,9.52 }, { "FSIF100",40.72,50.0,0.93 }, /* ** NORTH COAST ** */ { "NCE28",38.14,18.9,1.40 }, { "NCE50",37.35,18.9,0.76 }, { "NCF41",79.57,37.7,1.80 }, { "NCF75",75.34,37.7,0.97 }, /* ** U.S. ROCKETS ** */ { "USE6",37.55,21.5,7.45 }, { "USE10",39.80,21.0,4.06 }, { "USE25",38.14,18.9,1.40 }, { "USF9",49.76,24.5,5.05 }, { "USF20",74.88,37.7,4.07 }, { "USF10",74.64,40.7,7.39 }, { "USF80",75.34,37.7,0.97 }, { "USG25",119.05,62.5,4.86 }, /* ** VULCAN ** */ { "VE26",39.54,19.2,1.41 }, { "VG50",125.87,61.7,2.57 }, /* ** APOGEE ** */ { "AP1/4A3-XT",0.55,1.2,0.19 }, { "APA3-XT",2.02,3.3,0.69 }, /* ** PROP MASS NOT GIVEN BY NAR - ESTIMATED ** */ { "APC10",9.56,12.4,0.96 }, /* ** DUMMY LAST RECORD FOLLOWS - MUST BE PRESENT ** */ { "",0,0,0 }}; char WORK[100]; char ALTSW, ENG[100]; float TB, K, NETF, MAV, INITV, INITY; float VB, G, TC, YC, F, TOTIMP, MB, MROCKET, MP; float AX, D, RHOAIR1, RHOAIR, TEMPC, TEMPF, YTOT, MROCKET1; float YB, M, CD, MTOF, TOTALT, TOTALT1, D1, TOL, COMPARE, STANDARD, LSTCD; float CD1, DELTA, LSTCOMP, SLOPE, TA; void color_routine() { /* NOTE: For other systems, add your own routine */ #if(TURBODOS == 1) textmode(C80); textcolor(WHITE); textbackground(BLUE); #endif return; } void get_line(cp) char *cp; { int c; for (;;) { c = getchar(); if ((c >= 'a') && (c <= 'z')) c = c + 'A' - 'a'; if (c == EOF || c == '\n') { *cp = 0; return; } *cp++ = c; } } float get_val(cp) char *cp; { float res = 0; sscanf(cp, "%f", &res); return(res); } /* ** LOOKUP ROUTINE ** */ int lookup() { struct motor *motorp; for (motorp = &motors[0];motorp->name[0];motorp++) if (strcmp(ENG, motorp->name) == 0) { TOTIMP = motorp->impulse; MP = motorp->mp; TB = motorp->tb; return(1); } return(0); } /* ** BURNOUT ALTITUDE ** */ void burnout_alt() { float WORK; WORK = cosh(TB * sqrt(K * NETF) / MAV); WORK = WORK + INITV * sqrt(K / NETF) * sinh(TB * sqrt(K * NETF) / MAV); YB = MAV * log(WORK) / K + INITY; } /* ** BURNOUT VELOCITY ** */ void burnout_vel() { float WORK1, WORK2; WORK1 = tanh(TB * sqrt(K * NETF) / MAV); WORK2 = INITV * sqrt(K / NETF); VB = sqrt(NETF / K) * (WORK1 + WORK2) / (1 + WORK1 * WORK2); } /* ** COAST TIME ** */ void coast_time() { TC = sqrt(MB / (G * K)) * atan(VB * sqrt(K / (MB * G))); } /* ** COAST ALTITUDE ** */ void coast_alt() { YC = MB * log(K * VB * VB / (MB * G) + 1) / (K + K); } /* ** TRAJECTORY CALCULATION ROUTINE ** */ void trajectory() { F = TOTIMP / TB; INITV = 0; INITY = 0; MB = MROCKET - MP; if (MB < 0) MB = 0; MAV = MB + .5 * MP; NETF = F - MAV * G; AX = 3.14159265358979 * D * D / 4; K = AX * CD * RHOAIR * .5; burnout_alt(); /* ** BURNOUT ALTITUDE, YB ** */ burnout_vel(); /* ** BURNOUT VELOCITY, VB ** */ coast_time(); /* ** COAST TIME, TC ** */ coast_alt(); /* COAST ALTITUDE, YC ** */ YTOT = YB + YC; } /* ** PRINT ROUTINE ** */ void print() { printf("Total Altitude = %f Meters or %f Feet\n\r",YTOT, YTOT * MTOF); printf("Cutoff Altitude = %f Meters or %f Feet\n\r",YB, YB * MTOF); printf("\n\r"); printf("Cutoff Velocity = %f M/Sec or %f FT/Sec\n\r",VB, VB * MTOF); printf("Average Velocity = %f M/Sec or %f FT/Sec\n\r", YTOT / (TB+TC), YTOT * MTOF / (TB+TC)); printf("\n\r"); printf("Coast Time = %f Seconds\n\r",TC); printf("Ascent Time = %f Seconds\n\r",TC+TB); printf("\n\r"); printf("Cd = %f (no units)\n\r",CD); printf("Shape Constant (K)= %f Kg/M\n\r",K); } /* ** DRIVER ** */ void driver() { int go_on; for (;;) { CLS; printf(" *** BackTracked Trajectory Analysis Version 3.0 ***\n\r"); printf("\n\r"); printf("T = Temporal; O = Optical P = Predict (%c) ", ALTSW); get_line(WORK); if ((WORK[0] == ' ' || WORK[0] == 0) && (ALTSW != ' ')) break; if (WORK[0] == 'T') { ALTSW = 'T'; break; } if (WORK[0] == 'O') { ALTSW = 'O'; break; } if (WORK[0] == 'P') { ALTSW = 'P'; break; } } #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf("T = Temporal; O = Optical P = Predict (%c) \n\r", ALTSW); #endif printf("\n\r"); go_on = 1; while (go_on) { go_on = 0; #if (TEMPSW == 'F') printf("Temperature (Deg F) (%f) ",TEMPF); get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') TEMPF = get_val(WORK); TEMPC = (TEMPF - 32)*5/9; #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf("Temperature (Deg F) (%f) \n\r",TEMPF); #endif #else printf("Temperature (Deg C) (%f) ",TEMPC); get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') TEMPC = get_val(WORK); #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf("Temperature (Deg C) (%f) \n\r",TEMPC); #endif #endif RHOAIR = RHOAIR1*273.15/(273.15+TEMPC); #if(INUNITS == 'M') printf("Launch Mass (Grams) (%f) ",MROCKET1); #else printf("Launch Weight (Ounces) (%f) ",MROCKET1); #endif get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') MROCKET1 = get_val(WORK); MROCKET = MROCKET1 / 1000.0; #if(INUNITS == 'E') MROCKET = MROCKET * OZTOG; #endif #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); #if(INUNITS == 'M') printf("Launch Mass (Grams) (%f) \n\r",MROCKET1); #else printf("Launch Weight (Ounces) (%f) \n\r",MROCKET1); #endif #endif for (;;) { printf("Engine Type (%s) ", ENG); get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') strcpy(ENG, WORK); if (lookup()) break; } #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf("Engine Type (%s) \n\r", ENG); #endif MP = MP / 1000; if (MP > MROCKET) { printf("Rocket weighs more than the propellant ...\n\r"); go_on = 1; } } #if(INUNITS == 'M') printf("Body Diameter (Cm) (%f) ",D1); #else printf("Body Diameter (Inches) (%f) ",D1); #endif get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') { D1 = get_val(WORK); #if (INUNITS == 'M') D = D1 / 100; #else D = D1 * INCHTOM; #endif } #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); #if (INUNITS == 'M') printf("Body Diameter (Cm) (%f) \n\r",D1); #else printf("Body Diameter (Inches) (%f) \n\r",D1); #endif #endif if (ALTSW == 'T') { printf("Ascent Time (Seconds) (%f) ",TA); get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') { TA = get_val(WORK); } #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf("Ascent Time (Seconds) (%f) \n\r",TA); #endif } if (ALTSW == 'P') { printf("Drag Coefficient (No Units) (%f) ",CD1); get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') { CD1 = get_val(WORK); } #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf("Drag Coefficient (No Units) (%f) \n\r",CD1); #endif } if (ALTSW == 'O') { #if (ALTUNITS == 'F') printf("Altitude (Feet) (%f) ", TOTALT1); #else printf("Altitude (Meters) (%f) ", TOTALT1); #endif get_line(WORK); if (WORK[0] != 0 && WORK[0] != ' ') { TOTALT1 = get_val(WORK); #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); #if(ALTUNITS == 'M') printf("Altitude (Meters) (%f) \n\r", TOTALT1); #else printf("Altitude (Feet) (%f) \n\r", TOTALT1); #endif #endif } #if( ALTUNITS == 'F') TOTALT=TOTALT1/MTOF; #else TOTALT=TOTALT1; #endif; } printf("\n\n\r"); } void optmass() { float MDD, MUU, MIDM, DELTA, PNT, PNTLO, PNTHI; int IOPT, ISW; /* ** OPTIMAL MASS ROUTINE ** */ /* ** MDD IS M CORRESPONDING TO DOWNWARD SLOPE ** */ /* ** MUU IS M CORRESPONDING TO UPWARD SLOPE ** */ MDD = TOTIMP / (1.5 * G * TB); MROCKET = MDD; trajectory(); MUU = MP + MP; MROCKET = MUU; trajectory(); DELTA = .00001; IOPT = 1; ISW = 1; while (ISW) { MIDM = (MDD + MUU) / 2.0; MROCKET = MIDM; trajectory(); PNT = YTOT; MROCKET = MIDM - DELTA; trajectory(); PNTLO = PNT - YTOT; MROCKET = MIDM + DELTA; trajectory(); PNTHI = YTOT - PNT; if ( (PNTLO < 0) && (PNTHI < 0) ) MDD = MIDM; else if ( (PNTLO > 0) && (PNTHI > 0) ) MUU = MIDM; else { MROCKET = MIDM; trajectory(); ISW = 0; IOPT = IOPT + 1; if (IOPT > 1000) ISW = 0; } } if (IOPT > 1000) printf("*** NO CONVERGENCE ** \n\r"); return; } void main() { int go_on, i; INITV=0.0; G = 9.8; /* ** GRAVITATIONAL CONSTANT ** */ TEMPF=68; /* **** DEFAULT TEMPERATURES **** */ TEMPC=20; color_routine(); RHOAIR1 = 1.2929; /* ** AIR DENSITY AT 0 DEG C ** */ /* NOTE: Backtracked altitudes NOT dependent on this figure BUT Cd'd are */ ALTSW = 'T'; MTOF = 3.281; D1 = 0; for(;;) { TOL = .000001; driver(); CD = .01; trajectory(); if (ALTSW == 'T') { COMPARE = TC + TB; STANDARD = TA; } else if (ALTSW == 'O') { COMPARE = YB + YC; STANDARD = TOTALT; } else { COMPARE = CD; STANDARD=CD1; /* THEY DON'T CALL ME "KLUDGE CURCIO" FOR NOTHIN! */ } LSTCD = CD; CD = 2; i = 1; go_on = 1; while (go_on) { LSTCOMP = COMPARE; trajectory(); if (ALTSW == 'T') COMPARE = TC + TB; else if (ALTSW == 'O') COMPARE = YB + YC; else COMPARE = CD; DELTA = STANDARD - COMPARE; if ( (fabs(DELTA) / STANDARD) < TOL) go_on = 0; else { if (COMPARE != LSTCOMP) SLOPE = (CD - LSTCD) / (COMPARE - LSTCOMP); LSTCD = CD; CD = CD + (STANDARD - COMPARE) * SLOPE; if (CD <= 0) CD = .05; } if (i++ >= NUMREP) go_on = 0; } if (i >= NUMREP ) { printf(" ** FAILURE TO CONVERGE! ABNORMAL RESULT! **\n\r"); printf("\n\r"); } print(); if (ALTSW != 'T') TA = TB + TC; if (ALTSW != 'O') #if ( ALTUNITS == 'M') TOTALT1 = YB + YC; #else TOTALT1 = (YB + YC)*MTOF; #endif if (ALTSW != 'P') CD1 = CD; printf("\n\r"); WORK[0] = 'O'; while (WORK[0] == 'O') { printf( "Q = QUIT; O/OK = OPTIMIZE MASS; ANYTHING ELSE = NEXT RUN "); get_line(WORK); #if(TURBODOS == 1) gotoxy(1,wherey()-1); clreol(); printf( "Q = QUIT; O/OK = OPTIMIZE MASS; ANYTHING ELSE = NEXT RUN\n\r"); #endif if(( WORK[0] == 'O') || (WORK[0] == 'o')) { WORK[0] = 'O'; optmass(); CLS ; printf("\n\n\n\r"); printf( " **** Estimated Optimal Performance At "); #if (TEMPSW == 'F') printf ("%f Degrees F **** \n\n\r",TEMPF); #else printf ("%f Degrees C **** \n\n\r",TEMPC); #endif printf( " Optimal Mass = %f Grams or %f Ounces \n\n\r", MROCKET * 1000, MROCKET * 1000.0/OZTOG); print(); printf("\n\r"); if((WORK[1] == 'K') || (WORK[1] == 'k')) { MROCKET1 = MROCKET * 1000; #if(INUNITS == 'E') MROCKET1 = MROCKET1 / OZTOG; #endif ALTSW = 'P'; } } else if( (WORK[0] == 'q') || (WORK[0] == 'Q' )) return; } } }