├── .gitignore ├── Combust ├── Combust.py ├── Inject.py ├── Nozzle.py ├── Properties.py └── Thermo.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | Nozzle.py 3 | Thermo.py 4 | R7/Properties.py 5 | R7/Inject.py 6 | R7/Combust_7.py 7 | R6/Properties.py 8 | R6/Inject.py 9 | R6/Combust_6.py 10 | R5/Inject.py 11 | R5/Properties.py 12 | R4/Combust_4.py 13 | R5/Combust_5.py 14 | R3/Properties.py 15 | R3/Inject.py 16 | R3/Combust_3.py 17 | R2/Properties.py 18 | R2/Inject.py 19 | R1/Properties.py 20 | R2/Combust_2.py 21 | R1/Inject.py 22 | R1/Combust_1.py 23 | R0/Inject_1.py 24 | R0/Inject_0.py 25 | __pycache__/Inject.cpython-36.pyc 26 | *.pyc 27 | -------------------------------------------------------------------------------- /Combust/Combust.py: -------------------------------------------------------------------------------- 1 | """ 2 | 3 | Written by Jonny Hyman, 2017 4 | www.jonnyhyman.com 5 | 6 | Ref 0 http://digitalcommons.usu.edu/cgi/viewcontent.cgi?article=1079&context=mae_facpub 7 | Ref 1 http://www.d.umn.edu/~rrosandi/Hybrids/Reports/Numerical_Model.pdf 8 | Ref 2 http://www.enu.kz/repository/2011/AIAA-2011-5909.pdf 9 | Ref 3 https://www.fire.tc.faa.gov/pdf/05-14.pdf 10 | Ref 4 https://goo.gl/1Eh1Gf 11 | 12 | Rocket Propulsion Elements, https://goo.gl/kCFbHc 13 | 14 | This combustion model, given geometric and environmental inputs gives 15 | - Thrust, V2, ISP, Mass Flow, and other properties for ABS/N2O hybrids 16 | 17 | The caveat is that the INPUTs include: 18 | - Target chamber pressure 19 | - Target oxidizer/fuel ratio, both of which vary continuously, and are 20 | dependent on the output variables 21 | 22 | Given experimental data from 0, we observe that: 23 | - Efficiency is somewhat "over-estimated". Actual / Pred. ISP = 200s / 238s 24 | - Regression model holds some error, as seen by the fact that the O / F 25 | ratio input to the model does not equal the output O / F calculated 26 | by the regression model, when against test data 27 | 28 | Also, note that this is a steady-state / "startup" analysis, no provisions 29 | have been made yet to calculate dynamic behavior. 30 | 31 | Program execution is roughly: 32 | x = Injector() 33 | y includes x 34 | z = Thermo(y) 35 | show Nozzle(z) 36 | """ 37 | 38 | import numpy as np 39 | 40 | from Thermo import Thermo 41 | from Nozzle import Nozzle 42 | 43 | thermo = Thermo() 44 | nozzle = Nozzle() 45 | 46 | parameters = { 47 | 'v_dot' : 0, # m3/sec, tuned for O / F ratio 48 | 'rho_f' : 975, # kg/m3, fuel density 49 | 'rho_o' : 1.98, # kg/m3, oxidizer density 50 | 'p0' : 345*1e3*1.3, # pascals, oxidizer feed pressure 51 | 'p1_t' : 333*1e3, # pascals, chamber pressure target 52 | 'p3' : 95380, # pascals, atmospheric pressure 53 | 'R' : 0.010, # meters, port diameter 54 | 'Rt' : 0.010, # meters, throat diameter 55 | 'L' : 0.095, # meters 56 | 57 | # Injector parameters 58 | 'd' : 1.5e-3, # meters, injector orifice size 59 | 'Cd_ox' : 0.82, # injector discharge coefficient 60 | } 61 | 62 | # A_burn is the fuel grain surface area being burned 63 | parameters['A_burn'] = (2 * np.pi * parameters['R']) * parameters['L'] 64 | parameters['At'] = np.pi * (parameters['Rt'])**2 # throat area 65 | parameters['Ac'] = np.pi * (parameters['R'])**2 # fuel xsctn chamber area 66 | parameters['A_ox'] = np.pi * parameters['d']**2 # effective oxidizer area 67 | 68 | # Drives the entire shebang. Tune for desired thrust 69 | parameters['OF'] = 5.5 70 | 71 | if __name__ == '__main__': 72 | 73 | # Tune vdot until desired ox/fuel ratio is approximately met (within ~0.01) 74 | while abs(parameters['OF'] - thermo.evaluate(parameters)['OF']) > 0.01: 75 | 76 | difference = abs(parameters['OF'] - thermo.evaluate(parameters)['OF']) 77 | 78 | # proportional descent, may be gradient descent in the future 79 | parameters['v_dot'] += .0001*difference 80 | 81 | print("finding vdot ... O/F error:", '{:.02f}'.format(difference) ) 82 | 83 | therm = thermo.evaluate(parameters) 84 | F, v2, isp, mdot = nozzle.evaluate(therm) 85 | 86 | print() 87 | print(' Thrust: ', F, 'N') 88 | print(' v2 : ', v2, 'm/s') 89 | print(' ISP : ', isp, 'sec') 90 | print(' M Dot : ', mdot, 'kg/s') 91 | print(' P1 : ', therm['p1']*1e-3, 'kPa') 92 | print(' P1/P3 : ', therm['p1']/therm['p3']) 93 | print(' O / F : ', parameters['OF'],'=>',therm['OF']) 94 | print(' T0 : ', therm['T0'], 'K') 95 | print(' R Dot : ', thermo.regression*1e3, 'mm/s') 96 | print() 97 | print(' REQUIREMENTS') 98 | print(' V Dot : ', parameters['v_dot'], 'm3/s') 99 | print(' M Dot Ox :', thermo.mdot_o, 'kg/s') 100 | print(' M Dot H2O : ', parameters['v_dot']*1000, 'kg/s') 101 | 102 | # M Dot H2O represents the equivalent water mass flow rate at 103 | # equivalent feed / "top" pressure 104 | -------------------------------------------------------------------------------- /Combust/Inject.py: -------------------------------------------------------------------------------- 1 | """ 2 | NOTE: 3 | Utilize as a standalone calculator for injector - not tied to Combust.py 4 | 5 | Inputs: 6 | 7 | - Orifice diameter (d) 8 | - Experimental data: 9 | - Flow velocity (v) 10 | - Input pressure (p) 11 | 12 | Outputs: 13 | 14 | - Water mass flow rate 15 | - Volumetric flow rate 16 | - Nitrous mass flow rate 17 | 18 | Based on: https://en.wikipedia.org/wiki/Orifice_plate 19 | """ 20 | import numpy as np 21 | 22 | def evaluate(run): 23 | # vol. flow rate, kg/(sec * m**3) 24 | # mass flow rate, kg/sec 25 | 26 | qv = run['Cd'] / np.sqrt( 1 - ( run['d'] / run['D'] )**4 ) # first term 27 | qv = qv * 1 * np.pi * run['d']**2 # area and epsilon 28 | qv = qv * np.sqrt( 2*run['dP']/run['rho'] ) # pressure contribution 29 | 30 | qm = run['rho']*qv # mass flow rate 31 | 32 | return qv,qm 33 | 34 | injector = { 35 | 'rho': 1000, # kg/m**3 WATER 36 | 'D' : 3.175e-3, # pipe diameter, m 37 | 'd' : 1.5e-3, # hole diameter, m 38 | 'dP' : 172e3, # delta pressure, Pa 39 | 'Cd' : 0.82, # discharge coefficient, fit to measured dm/dt 40 | 'md' : 1.3, # kg/s 41 | } 42 | -------------------------------------------------------------------------------- /Combust/Nozzle.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import Properties as chem 3 | """ 4 | Ref 0 http://digitalcommons.usu.edu/cgi/viewcontent.cgi?article=1079&context=mae_facpub 5 | Ref 1 http://www.d.umn.edu/~rrosandi/Hybrids/Reports/Numerical_Model.pdf 6 | Ref 2 http://www.enu.kz/repository/2011/AIAA-2011-5909.pdf 7 | Ref 3 https://www.fire.tc.faa.gov/pdf/05-14.pdf 8 | Ref 4 https://goo.gl/1Eh1Gf 9 | 10 | Rocket Propulsion Elements, https://goo.gl/kCFbHc 11 | """ 12 | # ----------------------------------------------------- Nozzle Design Analysis 13 | class Nozzle(object): 14 | 15 | g0 = 9.80665 16 | 17 | def evaluate(n,input): 18 | """ Optimal nozzle design analysis """ 19 | 20 | mdot = input['mdot'] 21 | OF = input['OF'] 22 | p1 = input['p1'] 23 | p2 = input['p3'] # assume p2 == p3 24 | At = input['At'] 25 | k = input['k'] 26 | T0 = input['T0'] 27 | 28 | #--------------- v2 page 54, rocket propulsion elements 29 | 30 | m = np.interp(OF, chem.of, chem.m) 31 | R = 8314.3 # page 50, rocket propulsion elements 32 | 33 | # assumed p2=p3 34 | v2 = np.sqrt( 2*k/(k-1) * (R*T0 / m) * (1 - (p2/p1)**((k-1)/k)) ) 35 | 36 | #--------------- thrust page 36, rocket propulsion elements 37 | 38 | F = mdot * v2 39 | 40 | #--------------- specific impulse 41 | 42 | isp = F / (mdot*n.g0) 43 | 44 | return F, v2, isp, mdot 45 | -------------------------------------------------------------------------------- /Combust/Properties.py: -------------------------------------------------------------------------------- 1 | from numpy import array, arange 2 | 3 | # AVERAGE ACROSS PRESSURES, PERMISSIBLE ERROR = 5% ALL VARIABLES 4 | 5 | of = arange(1, 12.5, 0.5) 6 | 7 | # specific heat ratio 8 | k = array([ 9 | 1.22, # 1 10 | 1.23, # 1.5 11 | 1.23, # 2 12 | 1.23, # 2.5 13 | 1.27, # 3 14 | 1.24, # 3.5 15 | 1.22, # 4 16 | 1.18, # 4.5 17 | 1.16, # 5 18 | 1.15, # 5.5 19 | 1.14, # 6 20 | 1.14, # 6.5 21 | 1.14, # 7 22 | 1.14, # 7.5 23 | 1.14, # 8 24 | 1.14, # 8.5 25 | 1.14, # 9 26 | 1.14, # 9.5 27 | 1.14, # 10 28 | 1.14, # 10.5 29 | 1.14, # 11 30 | 1.15, # 11.5 31 | 1.15, # 12 32 | ]) 33 | 34 | # molecular weight, kg/kgmol 35 | m = array([ 36 | 22, # 1 37 | 22, # 1.5 38 | 22, # 2 39 | 22, # 2.5 40 | 22, # 3 41 | 23, # 3.5 42 | 24, # 4 43 | 25, # 4.5 44 | 25.75, # 5 45 | 26.25, # 5.5 46 | 26.75, # 6 47 | 27, # 6.5 48 | 27.5, # 7 49 | 27.75, # 7.5 50 | 28, # 8 51 | 28.1, # 8.5 52 | 28.25, # 9 53 | 28.4, # 9.5 54 | 28.5, # 10 55 | 28.7, # 10.5 56 | 28.8, # 11 57 | 28.9, # 11.5 58 | 29, # 12 59 | ]) 60 | 61 | # combustion characteristic, c*, m/sec 62 | cs = array([ 63 | 1250, # 1 64 | 1325, # 1.5 65 | 1400, # 2 66 | 1450, # 2.5 67 | 1500, # 3 68 | 1540, # 3.5 69 | 1575, # 4 70 | 1590, # 4.5 71 | 1600, # 5 72 | 1600, # 5.5 73 | 1590, # 6 74 | 1575, # 6.5 75 | 1570, # 7 76 | 1560, # 7.5 77 | 1550, # 8 78 | 1545, # 8.5 79 | 1525, # 9 80 | 1520, # 9.5 81 | 1515, # 10 82 | 1505, # 10.5 83 | 1500, # 11 84 | 1480, # 11.5 85 | 1475, # 12 86 | ]) 87 | 88 | # adiabatic flame temperature, K 89 | T0 = array([ 90 | 1800, # 1 91 | 2000, # 1.5 92 | 2200, # 2 93 | 2300, # 2.5 94 | 2600, # 3 95 | 2800, # 3.5 96 | 3000, # 4 97 | 3150, # 4.5 98 | 3200, # 5 99 | 3201, # 5.5 100 | 3202, # 6 101 | 3205, # 6.5 102 | 3202, # 7 103 | 3201, # 7.5 104 | 3200, # 8 105 | 3200, # 8.5 106 | 3200, # 9 107 | 3195, # 9.5 108 | 3190, # 10 109 | 3150, # 10.5 110 | 3110, # 11 111 | 3100, # 11.5 112 | 3100, # 12 113 | ]) 114 | 115 | # viscosity, Pa-sec 116 | mu = array([ 117 | .55, # 1 118 | .60, # 1.5 119 | .65, # 2 120 | .67, # 2.5 121 | .70, # 3 122 | .77, # 3.5 123 | .84, # 4 124 | .87, # 4.5 125 | .90, # 5 126 | .92, # 5.5 127 | .93, # 6 128 | .95, # 6.5 129 | .95, # 7 130 | .95, # 7.5 131 | .95, # 8 132 | .94, # 8.5 133 | .94, # 9 134 | .94, # 9.5 135 | .93, # 10 136 | .92, # 10.5 137 | .92, # 11 138 | .91, # 11.5 139 | .91, # 12 140 | ]) 141 | 142 | # Prandtl number 143 | Pr = array([ 144 | .50, # 1 145 | .51, # 1.5 146 | .51, # 2 147 | .50, # 2.5 148 | .47, # 3 149 | .43, # 3.5 150 | .40, # 4 151 | .40, # 4.5 152 | .44, # 5 153 | .45, # 5.5 154 | .46, # 6 155 | .47, # 6.5 156 | .48, # 7 157 | .50, # 7.5 158 | .51, # 8 159 | .51, # 8.5 160 | .52, # 9 161 | .52, # 9.5 162 | .53, # 10 163 | .53, # 10.5 164 | .54, # 11 165 | .54, # 11.5 166 | .55, # 12 167 | ]) 168 | 169 | if __name__ == '__main__': 170 | import matplotlib.pyplot as plt 171 | 172 | plt.plot(of, Pr) 173 | plt.show() 174 | -------------------------------------------------------------------------------- /Combust/Thermo.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import Properties as chem 3 | """ 4 | Ref 0 http://digitalcommons.usu.edu/cgi/viewcontent.cgi?article=1079&context=mae_facpub 5 | Ref 1 http://www.d.umn.edu/~rrosandi/Hybrids/Reports/Numerical_Model.pdf 6 | Ref 2 http://www.enu.kz/repository/2011/AIAA-2011-5909.pdf 7 | Ref 3 https://www.fire.tc.faa.gov/pdf/05-14.pdf 8 | Ref 4 https://goo.gl/1Eh1Gf 9 | 10 | Rocket Propulsion Elements, https://goo.gl/kCFbHc 11 | """ 12 | # ----------------------------------------------------- Thermochemical Analysis 13 | class Thermo(object): 14 | 15 | def __init__(t): 16 | 17 | # constants, adjusted from english -> metric [2] 18 | t.C0 = 0.047 19 | t.C1 = 4/5 20 | t.C2 = 0.153 21 | t.C3 = 1/5 22 | t.C4 = 0.23 23 | 24 | t.SLP = 101325 # pascals, 1 atm 25 | t.hv = 2.3*1e3*1e3 # heat of vaporization, kJ/g [3] -> J/kg 26 | t.cp = 1674.72 # [4], converted units to J/kgK 27 | t.Tfuel = 734.15 # [3], Table A-1, Tp, converted units to K 28 | 29 | def evaluate(t,input): 30 | """ Thermochemical analysis at a fixed time-slice """ 31 | 32 | OF = input['OF'] 33 | 34 | Pr = np.interp(OF, chem.of, chem.Pr) 35 | mu = np.interp(OF, chem.of, chem.mu) 36 | T0 = np.interp(OF, chem.of, chem.T0) 37 | k = np.interp(OF, chem.of, chem.k) 38 | 39 | thermo = {} 40 | 41 | rho_o = input['rho_o'] 42 | rho_f = input['rho_f'] 43 | Ac = input['Ac'] 44 | L = input['L'] 45 | p0 = input['p0'] # ox feed pressure 46 | p1 = input['p1_t'] # chamber pressure target 47 | mdot_o = input['v_dot']*rho_o # kg / sec 48 | 49 | #$ freestream propellant mass flow rate 50 | G = (input['A_ox']*input['Cd_ox'] / Ac) * np.sqrt(2*rho_o*(p0 - p1)) 51 | 52 | #$ nondimensional fuel mass flux / blowing coefficient 53 | B = t.cp * (T0-t.Tfuel) / t.hv 54 | 55 | #$ page 602, rocket propulsion elements 56 | #$ and page 19, reference 2: 57 | #$ units = m3/kg * (kg/m2s)*1/5 * (kg/m2s)*4/5 = m/s 58 | t.regression = t.C0*(G**t.C1)/(rho_f*Pr**t.C2)*(mu/L)**(t.C3)*(B**t.C4) 59 | 60 | # m2*kg/m3*m/s = kg/s 61 | mdot_f = input['A_burn'] * rho_f * t.regression 62 | 63 | # determine what the "modeled" OF is. Seems to trend higher than truth 64 | OF = mdot_o / mdot_f 65 | 66 | t.mdot_f = mdot_f 67 | t.mdot_o = mdot_o 68 | 69 | thermo['mdot'] = mdot_o + mdot_f 70 | thermo['At'] = input['At'] 71 | thermo['OF'] = OF 72 | thermo['k'] = k # specific heat ratio 73 | 74 | # assume stagnation pressure = chamber pressure, page 53 75 | thermo['p1'] = p1 76 | thermo['p3'] = input['p3'] 77 | thermo['T0'] = T0 78 | 79 | return thermo 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyBurn 2 | 3 | A Hybrid Rocket Motor Propulsion Model - Python 4 | 5 | + Combust.py : The primary run script, where all experimental / geometrical parameters are input 6 | + Thermo.py : Thermodynamical + some thermochemical calculations to determine combustion parameters 7 | + Nozzle.py : Isentropic flow through nozzles based on [5]. Determines thrust and efficiencies 8 | + Properties.py : Approximations of key thermochemical variables with respect to oxidizer/fuel ratio. Taken from [2], Fig 4 9 | + Inject.py : An orifice-plate model based injector flow rate calculator 10 | 11 | Currently, only supports analysis of ABS/N2O rocket motors. 12 | 13 | To run, call `python Combust.py` 14 | 15 | # References 16 | 17 | 0. http://digitalcommons.usu.edu/cgi/viewcontent.cgi?article=1079&context=mae_facpub 18 | 1. http://www.d.umn.edu/~rrosandi/Hybrids/Reports/Numerical_Model.pdf 19 | 2. http://www.enu.kz/repository/2011/AIAA-2011-5909.pdf 20 | 3. https://www.fire.tc.faa.gov/pdf/05-14.pdf 21 | 4. https://goo.gl/1Eh1Gf 22 | 5. Rocket Propulsion Elements, Sutton: https://goo.gl/kCFbHc 23 | --------------------------------------------------------------------------------