def test_te_exp_minus1(self): """Test Taylor expansion of e^x - 1""" x = Variable('x') self.assertEqual(te_exp_minus1(x, 1), x) self.assertEqual(te_exp_minus1(x, 3), x + x**2/2. + x**3/6.) self.assertRaises(ValueError, te_exp_minus1, x, 0) # make sure x was not modified self.assertEqual(x, Variable('x')) # try for VectorVariable too y = VectorVariable(3, 'y') self.assertEqual(te_exp_minus1(y, 1), y) self.assertEqual(te_exp_minus1(y, 3), y + y**2/2. + y**3/6.) self.assertRaises(ValueError, te_exp_minus1, y, 0) # make sure y was not modified self.assertEqual(y, VectorVariable(3, 'y'))
def test_te_exp_minus1(self): """Test Taylor expansion of e^x - 1""" x = Variable('x') self.assertEqual(te_exp_minus1(x, 1), x) self.assertEqual(te_exp_minus1(x, 3), x + x**2 / 2. + x**3 / 6.) self.assertRaises(ValueError, te_exp_minus1, x, 0) # make sure x was not modified self.assertEqual(x, Variable('x')) # try for VectorVariable too y = VectorVariable(3, 'y') self.assertEqual(te_exp_minus1(y, 1), y) self.assertEqual(te_exp_minus1(y, 3), y + y**2 / 2. + y**3 / 6.) self.assertRaises(ValueError, te_exp_minus1, y, 0) # make sure y was not modified self.assertEqual(y, VectorVariable(3, 'y'))
def setup(self, aircraft, state, **kwargs): self.aircraft = aircraft self.aircraftP = aircraft.dynamic(state) self.wingP = self.aircraftP.wingP self.fuseP = self.aircraftP.fuseP self.engineP = self.aircraftP.engineP #variable definitions z_bre = Variable('z_{bre}', '-', 'Breguet Parameter') Rng = Variable('Rng', 'nautical_miles', 'Cruise Segment Range') constraints = [] constraints.extend([ #steady level flight constraint on D self.aircraftP['D'] == aircraft['numeng'] * self.engineP['F'], #taylor series expansion to get the weight term TCS([self.aircraftP['W_{burn}']/self.aircraftP['W_{end}'] >= te_exp_minus1(z_bre, nterm=3)]), #breguet range eqn TCS([z_bre >= (self.engineP['TSFC'] * self.aircraftP['thr']* self.aircraftP['D']) / self.aircraftP['W_{avg}']]), #time self.aircraftP['thr'] * state['V'] == Rng, ]) return constraints, self.aircraftP
def setup(self, goods=None, bads=None, taylor_order=6): goods = goods if goods else {} goods.update({1 / k: 1 / v for k, v in bads.items()}) N = check_values_length(goods) exp_S = VectorVariable(N, "e^{S}") VectorVariable(N, "S") self.cost = 1 constraints = [[exp_S >= 1, exp_S.prod() == np.e]] for monomial, options in goods.items(): m_nd = Variable("|%s|" % monomial.latex(excluded=["models", "units"])) exp_m = Variable("e^{%s}" % m_nd.latex(excluded=["models"])) self.cost /= monomial if hasattr(options, "units"): monomial = monomial / (1 * options.units) options = options.magnitude options_scale = options.mean() options /= options_scale constraints.append([ m_nd == monomial / options_scale, (exp_S**options).prod() == exp_m, exp_m >= 1 + te_exp_minus1(m_nd, taylor_order), ]) return constraints
def setup(self, aircraft, state, **kwargs): self.aircraft = aircraft self.aircraftP = AircraftP(aircraft, state) self.wingP = self.aircraftP.wingP self.fuseP = self.aircraftP.fuseP #variable definitions z_bre = Variable('z_{bre}', '-', 'Breguet Parameter') Rng = Variable('Rng', 'nautical_miles', 'Cruise Segment Range') constraints = [] constraints.extend([ #taylor series expansion to get the weight term TCS([ self.aircraftP['W_{burn}'] / self.aircraftP['W_{end}'] >= te_exp_minus1(z_bre, nterm=3) ]), #time self.aircraftP['thr'] * state['V'] == Rng, self.aircraftP['W_{burn}'] == self.aircraft.engine['TSFC'][2:] * self.aircraft.engine['F'][:2:] * self.aircraftP['thr'] ]) return constraints, self.aircraftP
def setup(self, perf): z_bre = Variable("z_{bre}", "-", "Breguet coefficient") t = Variable("t", "days", "Time per flight segment") f_fueloil = Variable("f_{(fuel/oil)}", 0.98, "-", "Fuel-oil fraction") Wfuel = Variable("W_{fuel}", "lbf", "Segment-fuel weight") g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") constraints = [ TCS([ z_bre >= (perf["P_{total}"] * t * perf["BSFC"] * g / (perf["W_{end}"] * perf["W_{start}"])**0.5) ]), f_fueloil * Wfuel / perf["W_{end}"] >= te_exp_minus1(z_bre, 3), perf["W_{start}"] >= perf["W_{end}"] + Wfuel ] return constraints
def setup(self, Wstart, Wend, perf): z_bre = Variable("z_{bre}", "-", "Breguet coefficient") Wfuel = Variable("W_{fuel}", "lbf", "segment-fuel weight") g = Variable("g", 9.81, "m/s^2", "gravitational acceleration") R = Variable("R", "nautical_miles", "range") rhofuel = Variable("\\rho_{JetA}", 6.75, "lb/gallon", "Jet A fuel density") constraints = [ TCS([ z_bre >= (R * perf["\\dot{m}"] * rhofuel * g / perf["V"] / (Wend * Wstart)**0.5) ]), Wfuel / Wend >= te_exp_minus1(z_bre, 3), Wstart >= Wend + Wfuel ] return constraints
def setup(self, aircraft, state, **kwargs): self.aircraft = aircraft self.aircraftP = AircraftP(aircraft, state) self.wingP = self.aircraftP.wingP self.fuseP = self.aircraftP.fuseP self.engineP = self.aircraftP.engineP #variable definitions z_bre = Variable('z_{bre}', '-', 'Breguet Parameter') Rng = Variable('Rng', 'nautical_miles', 'Cruise Segment Range') constraints = [] constraints.extend([ #steady level flight constraint on D self.aircraftP['D'] == aircraft['numeng'] * self.engineP['thrust'], #taylor series expansion to get the weight term TCS([ self.aircraftP['W_{burn}'] / self.aircraftP['W_{end}'] >= te_exp_minus1(z_bre, nterm=3) ]), #breguet range eqn # old version -- possibly unneeded numeng # TCS([z_bre >= (self.aircraft['numeng'] * self.engineP['TSFC'] * self.aircraftP['thr']* # self.aircraftP['D']) / self.aircraftP['W_{avg}']]), # new version -- needs to be thought through carefully # seems correct to me - I switched T to D below (steady level flight) but fogot #about the Negn term TCS([ z_bre >= (self.engineP['TSFC'] * self.aircraftP['thr'] * self.aircraftP['D']) / self.aircraftP['W_{avg}'] ]), #time self.aircraftP['thr'] * state['V'] == Rng, ]) return constraints, self.aircraftP
def setup(self): # Fixed Parameters LD_max = Variable('\\left(\\frac{L}{D}\\right)_{max}', 15, '-', 'Maximum lift-to-drag ratio') MTOW = Variable('MTOW', 10000, 'lbf', 'Max takeoff weight') TSFC = Variable('TSFC', 0.307, 'lb/lbf/hr', 'Thrust specific fuel consumption') V_max = Variable('V_{max}', 420, 'knots', 'Maximum velocity') W_e = Variable('W_{e}', 7000, 'lbf', 'Operating empty weight') # Constants g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') # Free Variables LD = Variable('\\frac{L}{D}', '-', 'Lift-to-drag ratio') R = Variable('R', 'nautical_miles', 'Range') V = Variable('V', 'knots', 'Velocity') W_fuel = Variable('W_{fuel}', 'lbf', 'Fuel weight') W_init = Variable('W_{init}', 'lbf', 'Initial gross weight') z_bre = Variable('z_{bre}', '-', 'Breguet parameter') # Model objective = 1/R # Maximize range constraints = [# Aircraft and fuel weight W_init >= W_e + W_fuel, # Performance constraints W_init <= MTOW, LD <= LD_max, V <= V_max, # Breguet range R <= z_bre*LD*V/(TSFC*g), # Taylor series expansion of exp(z_bre) - 1 W_fuel/W_e >= te_exp_minus1(z_bre, nterm=3) ] return objective, constraints
def __init__(self, **kwargs): T_tp = 216.65 k = GRAVITATIONAL_ACCEL/(GAS_CONSTANT*T_tp) p11 = Variable('p_{11}', 22630, 'Pa', 'Pressure at 11 km') objective = 1/rho # maximize density constraints = [h >= 11*units.km, h <= 20*units.km, # Temperature is constant in the tropopause T == T_tp, # Pressure-altitude relation, using taylor series exp TCS([np.exp(k*11000)*p11/p >= 1 + te_exp_minus1(g/(R*T)*h, 15)], reltol=1E-4), # Ideal gas law rho == p/(R*T), ] su = Sutherland() lc = su.link(constraints) Model.__init__(self, objective, lc, **kwargs)
def __init__(self): CL = Variable('C_L', '-', 'Lift coefficient') CLmax = Variable('C_{L_{max}}', '-', 'Max lift coefficient') CD = Variable('C_D', '-', 'Drag coefficient') D = Variable('D', 'N', 'Total aircraft drag (cruise)') Dfuse = Variable('D_{fuse}', 'N', 'Fuselage drag') Dht = Variable('D_{ht}', 'N', 'Horizontal tail drag') Dvt = Variable('D_{vt}', 'N', 'Vertical tail drag') Dwing = Variable('D_{wing}', 'N', 'Wing drag') LD = Variable('\\frac{L}{D}', '-', 'Lift/drag ratio') Lh = Variable('L_h', 'N', 'Horizontal tail downforce') Lw = Variable('L_w', 'N', 'Wing lift') M = Variable('M', '-', 'Cruise Mach number') R = Variable('Range', 'nautical_miles', 'Range') Sw = Variable('S_w', 'm**2', 'Wing reference area') Te = Variable('T_e', 'N', 'Engine thrust at takeoff') TSFC = Variable('c_T', 'lb/lbf/hr', 'Thrust specific fuel consumption') V = Variable('V_{\\infty}', 'm/s', 'Cruise velocity') VTO = Variable('V_{TO}', 'm/s', 'Takeoff speed') W = Variable('W', 'N', 'Total aircraft weight') Weng = Variable('W_{eng}', 'N', 'Engine weight') Wfuel = Variable('W_{fuel}', 'N', 'Fuel weight') Wfuse = Variable('W_{fuse}', 'N', 'Fuselage weight') Wht = Variable('W_{ht}', 'N', 'Horizontal tail weight') Wlg = Variable('W_{lg}', 'N', 'Landing gear weight') Wpay = Variable('W_{pay}', 'N', 'Payload weight') Wvt = Variable('W_{vt}', 'N', 'Vertical tail weight') Wwing = Variable('W_{wing}', 'N', 'Wing weight') Wzf = Variable('W_{zf}', 'N', 'Zero fuel weight') a = Variable('a', 'm/s', 'Speed of sound (35,000 ft)') g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') lr = Variable('l_r', 5000, 'ft', 'Runway length') rho = Variable('\\rho', 'kg/m^3', 'Air density (cruise)') rho0 = Variable('\\rho_0', 'kg/m^3', 'Air density (sea level)') xCG = Variable('x_{CG}', 'm', 'x-location of CG') xCGeng = Variable('x_{CG_{eng}}', 'm', 'x-location of engine CG') xCGfu = Variable('x_{CG_{fu}}', 'm', 'x-location of fuselage CG') xCGht = Variable('x_{CG_{ht}}', 'm', 'x-location of htail CG') xCGlg = Variable('x_{CG_{lg}}', 'm', 'x-location of landing gear CG') xCGvt = Variable('x_{CG_{vt}}', 'm', 'x-location of vtail CG') xCGwing = Variable('x_{CG_{wing}}', 'm', 'x-location of wing CG') xTO = Variable('x_{TO}', 'm', 'Takeoff distance') xi = Variable('\\xi', '-', 'Takeoff parameter') xw = Variable('x_w', 'm', 'x-location of wing aerodynamic center') y = Variable('y', '-', 'Takeoff parameter') z_bre = Variable('z_{bre}', '-', 'Breguet parameter') with SignomialsEnabled(): objective = Wfuel # High level constraints hlc = [ # Drag and weight buildup D >= Dvt + Dfuse + Dwing + Dht, Wzf >= Wvt + Wfuse + Wlg + Wwing + Wht + Weng + Wpay, W >= Wzf + Wfuel, # Range equation for a jet V == M*a, D == 0.5*rho*V**2*Sw*CD, W == 0.5*rho*V**2*Sw*CL, LD == CL/CD, Lw >= W, # TODO: add Lh R <= z_bre*LD*V/(TSFC*g), Wfuel/Wzf >= te_exp_minus1(z_bre, nterm=3), # CG relationships TCS([xCG*W >= Wvt*xCGvt + Wfuse*xCGfu + Wlg*xCGlg + Wwing*xCGwing + Wht*xCGht + Weng*xCGeng + Wfuel*xCGwing + Wpay*xCGfu], reltol=1E-2, raiseerror=False), xw == xCGwing, xCGeng == xCGwing, #Takeoff relationships xi >= 0.5*rho0*VTO**2*Sw*CD/Te, 4*g*xTO*Te/(W*VTO**2) >= 1 + y, 1 >= 0.0464*xi**2.73/y**2.88 + 1.044*xi**0.296/y**0.049, VTO == 1.2*(2*W/(rho0*Sw*CLmax))**0.5, xTO <= lr, ] # Subsystem models vt = VerticalTail.coupled737() fu = Fuselage.coupled737() lg = LandingGear.coupled737() ht = HorizontalTail.coupled737() wi = Wing.coupled737() wb = WingBox() substitutions = { 'C_{L_{max}}': 2.5, 'M': 0.78, 'Range': 3000, 'c_T': 0.3, 'W_{eng}': 10000, 'a': 297, } lc = LinkedConstraintSet([hlc, vt, fu, lg, ht, wi], exclude=[vk.name for vk in wb.varkeys if not vk.value]) Model.__init__(self, objective, lc, substitutions)
# Constants g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') rho = Variable('\\rho', 0.4, 'kg/m^3', 'Air density at 33,000 ft') rho_sl = Variable('\\rho_{SL}', 1.225, 'kg/m^3', 'Air density at sea level') # Model objective = 1 / R # Maximize range constraints = [ # Weight buildup W >= W_e + W_pay + W_fuel, W_e >= f_str * W, # Breguet range R <= z_bre * CL / CD * V / (TSFC * g), # Taylor series expansion of exp(z_bre) - 1 W_fuel / W_e >= te_exp_minus1(z_bre, nterm=3), # Wing geometry AR == b**2 / S, b <= bmax, # Steady level flight W == 0.5 * rho * V**2 * S * CL, T == 0.5 * rho * V**2 * S * CD, T <= T_max, # Drag buildup CD >= CD0 + CL**2 / (np.pi * e * AR), # Speed limited by compressible drag rise M == V / a,
+ W_electrical + W_avionics + W_furnishings + W_air_conditioning + W_handling_gear + W_anti_ice + W_military_cargo_handling_system + Nen * Wen ) ] # Weights constraints += [ W_maximum_gross >= W_operating_empty + Wc + W_fuel, zbre >= R * (SFC/V) * (D/L), W_fuel >= W_operating_empty*te_exp_minus1(zbre,4), W_landing_gross >= .7 * W_maximum_gross ] # # Performance Model constraints += [ L == 1./2 * rho * V**2 * CL * S, L == W_maximum_gross, D == 1./2 * rho * V**2 * CD * S, S >= Saft + Scab + Sw , ] # Aerodynamic Model constraints += [ Re == rho*V*chord/mu, M == V/a,
def setup(self): constraints = [] # Steady level flight relations CD = Variable('C_D', '-', 'Drag coefficient') CL = Variable('C_L', '-', 'Lift coefficient') P_shaft = Variable('P_{shaft}', 'W', 'Shaft power') S = Variable('S', 'm^2', 'Wing reference area') V = Variable('V', 'm/s', 'Cruise velocity') W = Variable('W', 'lbf', 'Aircraft weight') eta_prop = Variable(r'\eta_{prop}', 0.7, '-', 'Propulsive efficiency') rho = Variable(r'\rho', 'kg/m^3') constraints.extend([P_shaft == V*W*CD/CL/eta_prop, # eta*P = D*V W == 0.5*rho*V**2*CL*S]) # Aerodynamics model Cd0 = Variable('C_{d0}', 0.01, '-', "non-wing drag coefficient") CLmax = Variable('C_{L-max}', 1.5, '-', 'maximum lift coefficient') e = Variable('e', 0.9, '-', "spanwise efficiency") A = Variable('A', 20, '-', "aspect ratio") b = Variable('b', 'ft', 'span') mu = Variable(r'\mu', 1.5e-5, 'N*s/m^2', "dynamic viscosity") Re = Variable("Re", '-', "Reynolds number") Cf = Variable("C_f", "-", "wing skin friction coefficient") Kwing = Variable("K_{wing}", 1.3, "-", "wing form factor") cl_16 = Variable("cl_{16}", 0.0001, "-", "profile stall coefficient") constraints.extend([CD >= Cd0 + 2*Cf*Kwing + CL**2/(pi*e*A) + cl_16*CL**16, b**2 == S*A, CL <= CLmax, Re == rho*V/mu*(S/A)**0.5, Cf >= 0.074/Re**0.2]) # Engine Weight Model W_eng = Variable('W_{eng}', 'lbf', 'Engine weight') W_engmin = Variable('W_{min}', 1.3, 'lbf', 'min engine weight') W_engmax = Variable('W_{max}', 275, 'lbf', 'max engine weight') eta_t = Variable('\\eta_t', 0.75, '-', 'percent throttle') eng_cnst = Variable('eng_{cnst}', 0.0011, '-', 'engine constant based off of power weight model') constraints.extend([W_eng >= W_engmin, W_eng <= W_engmax, W_eng >= P_shaft*eng_cnst/eta_t * units('lbf/watt')]) # Weight model W_airframe = Variable('W_{airframe}', 'lbf', 'Airframe weight') W_pay = Variable(r'W_{pay}', 4, 'lbf', 'Payload weight') W_fuel = Variable('W_{fuel}', 'lbf', 'Fuel Weight') W_zfw = Variable('W_{zfw}', 'lbf', 'Zero fuel weight') wl = Variable('wl', 'lbf/ft^2', 'wing loading') f_airframe = Variable('f_{airframe}', 0.3, '-', 'Airframe weight fraction') g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') constraints.extend([W_airframe >= W*f_airframe, W_zfw >= W_airframe + W_eng + W_pay, wl == W/S, W >= W_pay + W_eng + W_airframe + W_fuel]) # Breguet Range z_bre = Variable("z_bre", "-", "breguet coefficient") h_fuel = Variable("h_{fuel}", 42e6, "J/kg", "heat of combustion") eta_0 = Variable("\\eta_0", 0.2, "-", "overall efficiency") t = Variable('t', 7, 'days', 'time on station') constraints.extend([z_bre >= g*t*V*CD/(h_fuel*eta_0*CL), W_fuel/W_zfw >= te_exp_minus1(z_bre, 3)]) # Atmosphere model h = Variable("h", "ft", "Altitude") p_sl = Variable("p_{sl}", 101325, "Pa", "Pressure at sea level") T_sl = Variable("T_{sl}", 288.15, "K", "Temperature at sea level") L_atm = Variable("L_{atm}", 0.0065, "K/m", "Temperature lapse rate") T_atm = Variable("T_{atm}", "K", "air temperature") M_atm = Variable("M_{atm}", 0.0289644, "kg/mol", "Molar mass of dry air") R_atm = Variable("R_{atm}", 8.31447, "J/mol/K") TH = (g*M_atm/R_atm/L_atm).value.magnitude # dimensionless constraints.extend([h <= 20000*units.m, # Model valid to top of troposphere T_sl >= T_atm + L_atm*h, # Temp decreases w/ altitude rho <= p_sl*T_atm**(TH-1)*M_atm/R_atm/(T_sl**TH)]) # http://en.wikipedia.org/wiki/Density_of_air#Altitude # station keeping requirement footprint = Variable("d_{footprint}", 100, 'km', "station keeping footprint diameter") lu = Variable(r"\theta_{look-up}", 5, '-', "look up angle") R_earth = Variable("R_{earth}", 6371, "km", "Radius of earth") tan_lu = lu*pi/180. + (lu*pi/180.)**3/3. # Taylor series expansion # approximate earth curvature penalty as distance^2/(2*Re) constraints.extend([ h >= tan_lu*0.5*footprint + footprint**2/8./R_earth]) # wind speed model V_wind = Variable('V_{wind}', 'm/s', 'wind speed') wd_cnst = Variable('wd_{cnst}', [0.002, 0.0015], 'm/s/ft', 'wind speed constant predited by model') wd_ln = Variable('wd_{ln}', [13.009, 8.845], 'm/s', 'linear wind speed variable') h_min = Variable('h_{min}', 11800, 'ft', 'minimum height') h_max = Variable('h_{max}', 20800, 'ft', 'maximum height') constraints.extend([V_wind >= wd_cnst*h + wd_ln, # model predicting worse case scenario at 45 deg latitude V >= V_wind, h >= h_min, h <= h_max]) objective = W return objective, constraints
m_structures = VectorVariable(n_stages,"m_structures","kg") m_dot = VectorVariable(n_stages,"m_dot","kg/s") v_exhaust_effective = VectorVariable(n_stages,"v_exhaust_effective","m/s") F_thrust = VectorVariable(n_stages,"F_thrust","N") total_mass = VectorVariable(n_stages,"total_mass","kg") m_total = Variable("m_total","kg") g = Variable("g",9.8,"m/s/s") constraints = [] for stage in range(n_stages): constraints += [ Isp[stage] == v_exhaust_effective[stage]/g, m_dot[stage] == F_thrust[stage]/(g*Isp[stage]), z[stage] >= (dV[stage]+g*(m_fuel[stage]/m_dot[stage]))/v_exhaust_effective[stage], theta_fuel[stage] >= te_exp_minus1(z[stage],5) ] if stage == 0: constraints+=[F_thrust[stage]/g >= total_mass[stage], total_mass[stage] >= m_fuel[stage]+m_fuel[stage+1]+m_structures[stage]+m_structures[stage+1]+m_payload, m_structures[stage] == 0.02*m_fuel[stage], theta_fuel[stage] == m_fuel[stage]/total_mass[stage]] if stage == 1: constraints+=[F_thrust[stage]/g >= total_mass[stage], total_mass[stage] >= m_fuel[stage]+m_structures[stage] + m_payload, m_structures[stage] == 0.02*m_fuel[stage], theta_fuel[stage] == m_fuel[stage]/total_mass[stage]] constraints+=[ m_total >= m_structures[0] + m_fuel[0] + m_structures[1] + m_fuel[1] + m_payload]
constraints += [ W_operating_empty >= (W_centerbody + W_afterbody + W_wing + W_vertical_tail + W_main_landing_gear + W_nose_landing_gear + W_engine_contents + W_nacelle_group + W_engine_controls + W_starter_penumatic + W_fuel_system + W_flight_controls + W_APU_installed + W_instruments + W_hydraulics + W_electrical + W_avionics + W_furnishings + W_air_conditioning + W_handling_gear + W_anti_ice + W_military_cargo_handling_system + Nen * Wen) ] # Weights constraints += [ W_maximum_gross >= W_operating_empty + Wc + W_fuel, zbre >= R * (SFC / V) * (D / L), W_fuel >= W_operating_empty * te_exp_minus1(zbre, 4), W_landing_gross >= .7 * W_maximum_gross ] # # Performance Model constraints += [ L == 1. / 2 * rho * V**2 * CL * S, L == W_maximum_gross, D == 1. / 2 * rho * V**2 * CD * S, S >= Saft + Scab + Sw, ] # Aerodynamic Model constraints += [ Re == rho * V * chord / mu, M == V / a,
# Constants g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') rho = Variable('\\rho', 0.4, 'kg/m^3', 'Air density at 33,000 ft') rho_sl = Variable('\\rho_{SL}', 1.225, 'kg/m^3', 'Air density at sea level') # Model objective = 1/R # Maximize range constraints = [# Weight buildup W >= W_e + W_pay + W_fuel, W_e >= f_str*W, # Breguet range R <= z_bre*CL/CD*V/(TSFC*g), # Taylor series expansion of exp(z_bre) - 1 W_fuel/W_e >= te_exp_minus1(z_bre, nterm=3), # Wing geometry AR == b**2/S, b <= bmax, # Steady level flight W == 0.5*rho*V**2*S*CL, T == 0.5*rho*V**2*S*CD, T <= T_max, # Drag buildup CD >= CD0 + CL**2/(np.pi*e*AR), # Speed limited by compressible drag rise M == V/a,
def setup(self): constraints = [] # Steady level flight relations CD = Variable('C_D', '-', 'Drag coefficient') CL = Variable('C_L', '-', 'Lift coefficient') P_shaft = Variable('P_{shaft}', 'W', 'Shaft power') S = Variable('S', 'm^2', 'Wing reference area') V = Variable('V', 'm/s', 'Cruise velocity') W = Variable('W', 'lbf', 'Aircraft weight') eta_prop = Variable(r'\eta_{prop}', 0.7, '-', 'Propulsive efficiency') rho = Variable(r'\rho', 'kg/m^3') constraints.extend([ P_shaft == V * W * CD / CL / eta_prop, # eta*P = D*V W == 0.5 * rho * V**2 * CL * S ]) # Aerodynamics model Cd0 = Variable('C_{d0}', 0.01, '-', "non-wing drag coefficient") CLmax = Variable('C_{L-max}', 1.5, '-', 'maximum lift coefficient') e = Variable('e', 0.9, '-', "spanwise efficiency") A = Variable('A', 20, '-', "aspect ratio") b = Variable('b', 'ft', 'span') mu = Variable(r'\mu', 1.5e-5, 'N*s/m^2', "dynamic viscosity") Re = Variable("Re", '-', "Reynolds number") Cf = Variable("C_f", "-", "wing skin friction coefficient") Kwing = Variable("K_{wing}", 1.3, "-", "wing form factor") cl_16 = Variable("cl_{16}", 0.0001, "-", "profile stall coefficient") constraints.extend([ CD >= Cd0 + 2 * Cf * Kwing + CL**2 / (pi * e * A) + cl_16 * CL**16, b**2 == S * A, CL <= CLmax, Re == rho * V / mu * (S / A)**0.5, Cf >= 0.074 / Re**0.2 ]) # Engine Weight Model W_eng = Variable('W_{eng}', 'lbf', 'Engine weight') W_engmin = Variable('W_{min}', 1.3, 'lbf', 'min engine weight') W_engmax = Variable('W_{max}', 275, 'lbf', 'max engine weight') eta_t = Variable('\\eta_t', 0.75, '-', 'percent throttle') eng_cnst = Variable('eng_{cnst}', 0.0011, '-', 'engine constant based off of power weight model') constraints.extend([ W_eng >= W_engmin, W_eng <= W_engmax, W_eng >= P_shaft * eng_cnst / eta_t * units('lbf/watt') ]) # Weight model W_airframe = Variable('W_{airframe}', 'lbf', 'Airframe weight') W_pay = Variable(r'W_{pay}', 4, 'lbf', 'Payload weight') W_fuel = Variable('W_{fuel}', 'lbf', 'Fuel Weight') W_zfw = Variable('W_{zfw}', 'lbf', 'Zero fuel weight') wl = Variable('wl', 'lbf/ft^2', 'wing loading') f_airframe = Variable('f_{airframe}', 0.3, '-', 'Airframe weight fraction') g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') constraints.extend([ W_airframe >= W * f_airframe, W_zfw >= W_airframe + W_eng + W_pay, wl == W / S, W >= W_pay + W_eng + W_airframe + W_fuel ]) # Breguet Range z_bre = Variable("z_bre", "-", "breguet coefficient") h_fuel = Variable("h_{fuel}", 42e6, "J/kg", "heat of combustion") eta_0 = Variable("\\eta_0", 0.2, "-", "overall efficiency") t = Variable('t', 7, 'days', 'time on station') constraints.extend([ z_bre >= g * t * V * CD / (h_fuel * eta_0 * CL), W_fuel / W_zfw >= te_exp_minus1(z_bre, 3) ]) # Atmosphere model h = Variable("h", "ft", "Altitude") p_sl = Variable("p_{sl}", 101325, "Pa", "Pressure at sea level") T_sl = Variable("T_{sl}", 288.15, "K", "Temperature at sea level") L_atm = Variable("L_{atm}", 0.0065, "K/m", "Temperature lapse rate") T_atm = Variable("T_{atm}", "K", "air temperature") M_atm = Variable("M_{atm}", 0.0289644, "kg/mol", "Molar mass of dry air") R_atm = Variable("R_{atm}", 8.31447, "J/mol/K") TH = (g * M_atm / R_atm / L_atm).value.magnitude # dimensionless constraints.extend([ h <= 20000 * units.m, # Model valid to top of troposphere T_sl >= T_atm + L_atm * h, # Temp decreases w/ altitude rho <= p_sl * T_atm**(TH - 1) * M_atm / R_atm / (T_sl**TH) ]) # http://en.wikipedia.org/wiki/Density_of_air#Altitude # station keeping requirement footprint = Variable("d_{footprint}", 100, 'km', "station keeping footprint diameter") lu = Variable(r"\theta_{look-up}", 5, '-', "look up angle") R_earth = Variable("R_{earth}", 6371, "km", "Radius of earth") tan_lu = lu * pi / 180. + (lu * pi / 180.)**3 / 3. # Taylor series expansion # approximate earth curvature penalty as distance^2/(2*Re) constraints.extend( [h >= tan_lu * 0.5 * footprint + footprint**2 / 8. / R_earth]) # wind speed model V_wind = Variable('V_{wind}', 'm/s', 'wind speed') wd_cnst = Variable('wd_{cnst}', [0.002, 0.0015], 'm/s/ft', 'wind speed constant predited by model') wd_ln = Variable('wd_{ln}', [13.009, 8.845], 'm/s', 'linear wind speed variable') h_min = Variable('h_{min}', 11800, 'ft', 'minimum height') h_max = Variable('h_{max}', 20800, 'ft', 'maximum height') constraints.extend([ V_wind >= wd_cnst * h + wd_ln, # model predicting worse case scenario at 45 deg latitude V >= V_wind, h >= h_min, h <= h_max ]) objective = W return objective, constraints