diff --git a/.gitignore b/.gitignore index ab983c66..34976985 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ +# documentation temp files +*.md.py +*.aux +*.generated.tex +*.md.tex.md + # iPython checkpoint folders .ipynb_checkpoints/ diff --git a/1682/build.sh b/1682/build.sh new file mode 100755 index 00000000..80124871 --- /dev/null +++ b/1682/build.sh @@ -0,0 +1,4 @@ +python -c 'import gpkit; exec gpkit.mdmake("gas_hale.md")' +pandoc --template default.latex gas_hale.md.tex.md -o gas_hale.pdf + + diff --git a/1682/default.latex b/1682/default.latex new file mode 100644 index 00000000..bef63549 --- /dev/null +++ b/1682/default.latex @@ -0,0 +1,263 @@ +\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$paper,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$} +$if(fontfamily)$ +\usepackage[$for(fontfamilyoptions)$$fontfamilyoptions$$sep$,$endfor$]{$fontfamily$} +$else$ +\usepackage{lmodern} +$endif$ +$if(linestretch)$ +\usepackage{setspace} +\setstretch{$linestretch$} +$endif$ +\usepackage{amssymb,amsmath} +\usepackage{ifxetex,ifluatex} +\usepackage{fixltx2e} % provides \textsubscript +\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex + \usepackage[$if(fontenc)$$fontenc$$else$T1$endif$]{fontenc} + \usepackage[utf8]{inputenc} +$if(euro)$ + \usepackage{eurosym} +$endif$ +\else % if luatex or xelatex + \ifxetex + \usepackage{mathspec} + \else + \usepackage{fontspec} + \fi + \defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase} +$if(euro)$ + \newcommand{\euro}{€} +$endif$ +$if(mainfont)$ + \setmainfont[$for(mainfontoptions)$$mainfontoptions$$sep$,$endfor$]{$mainfont$} +$endif$ +$if(sansfont)$ + \setsansfont[$for(sansfontoptions)$$sansfontoptions$$sep$,$endfor$]{$sansfont$} +$endif$ +$if(monofont)$ + \setmonofont[Mapping=tex-ansi$if(monofontoptions)$,$for(monofontoptions)$$monofontoptions$$sep$,$endfor$$endif$]{$monofont$} +$endif$ +$if(mathfont)$ + \setmathfont(Digits,Latin,Greek)[$for(mathfontoptions)$$mathfontoptions$$sep$,$endfor$]{$mathfont$} +$endif$ +$if(CJKmainfont)$ + \usepackage{xeCJK} + \setCJKmainfont[$for(CJKoptions)$$CJKoptions$$sep$,$endfor$]{$CJKmainfont$} +$endif$ +\fi +% use upquote if available, for straight quotes in verbatim environments +\IfFileExists{upquote.sty}{\usepackage{upquote}}{} +% use microtype if available +\IfFileExists{microtype.sty}{% +\usepackage{microtype} +\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts +}{} +$if(geometry)$ +\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry} +$endif$ +\usepackage{hyperref} +$if(colorlinks)$ +\PassOptionsToPackage{usenames,dvipsnames}{color} % color is loaded by hyperref +$endif$ +\hypersetup{unicode=true, +$if(title-meta)$ + pdftitle={$title-meta$}, +$endif$ +$if(author-meta)$ + pdfauthor={$author-meta$}, +$endif$ +$if(keywords)$ + pdfkeywords={$for(keywords)$$keywords$$sep$; $endfor$}, +$endif$ +$if(colorlinks)$ + colorlinks=true, + linkcolor=$if(linkcolor)$$linkcolor$$else$Maroon$endif$, + citecolor=$if(citecolor)$$citecolor$$else$Blue$endif$, + urlcolor=$if(urlcolor)$$urlcolor$$else$Blue$endif$, +$else$ + pdfborder={0 0 0}, +$endif$ + breaklinks=true} +\urlstyle{same} % don't use monospace font for urls +$if(lang)$ +\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex + \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel} +$if(babel-newcommands)$ + $babel-newcommands$ +$endif$ +\else + \usepackage{polyglossia} + \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$} +$for(polyglossia-otherlangs)$ + \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$} +$endfor$ +\fi +$endif$ +$if(natbib)$ +\usepackage{natbib} +\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$} +$endif$ +$if(biblatex)$ +\usepackage$if(biblio-style)$[style=$biblio-style$]$endif${biblatex} +$if(biblatexoptions)$\ExecuteBibliographyOptions{$for(biblatexoptions)$$biblatexoptions$$sep$,$endfor$}$endif$ +$for(bibliography)$ +\addbibresource{$bibliography$} +$endfor$ +$endif$ +$if(listings)$ +\usepackage{listings} +$endif$ +$if(lhs)$ +\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{} +$endif$ +$if(highlighting-macros)$ +$highlighting-macros$ +$endif$ +$if(verbatim-in-note)$ +\usepackage{fancyvrb} +\VerbatimFootnotes % allows verbatim text in footnotes +$endif$ +$if(tables)$ +\usepackage{longtable,booktabs} +$endif$ +$if(graphics)$ +\usepackage{graphicx,grffile} +\makeatletter +\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi} +\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi} +\makeatother +% Scale images if necessary, so that they will not overflow the page +% margins by default, and it is still possible to overwrite the defaults +% using explicit options in \includegraphics[width, height, ...]{} +\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio} +$endif$ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% ADD YOUR \usepackage{...} COMMANDS HERE +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\usepackage{longtable} +\usepackage{booktabs} + +$if(links-as-notes)$ +% Make links footnotes instead of hotlinks: +\renewcommand{\href}[2]{#2\footnote{\url{#1}}} +$endif$ +$if(strikeout)$ +\usepackage[normalem]{ulem} +% avoid problems with \sout in headers with hyperref: +\pdfstringdefDisableCommands{\renewcommand{\sout}{}} +$endif$ +$if(indent)$ +$else$ +\IfFileExists{parskip.sty}{% +\usepackage{parskip} +}{% else +\setlength{\parindent}{0pt} +\setlength{\parskip}{6pt plus 2pt minus 1pt} +} +$endif$ +\setlength{\emergencystretch}{3em} % prevent overfull lines +\providecommand{\tightlist}{% + \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}} +$if(numbersections)$ +\setcounter{secnumdepth}{5} +$else$ +\setcounter{secnumdepth}{0} +$endif$ +$if(subparagraph)$ +$else$ +% Redefines (sub)paragraphs to behave more like sections +\ifx\paragraph\undefined\else +\let\oldparagraph\paragraph +\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}} +\fi +\ifx\subparagraph\undefined\else +\let\oldsubparagraph\subparagraph +\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}} +\fi +$endif$ +$if(dir)$ +\ifxetex + % load bidi as late as possible as it modifies e.g. graphicx + $if(latex-dir-rtl)$ + \usepackage[RTLdocument]{bidi} + $else$ + \usepackage{bidi} + $endif$ +\fi +\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex + \TeXXeTstate=1 + \newcommand{\RL}[1]{\beginR #1\endR} + \newcommand{\LR}[1]{\beginL #1\endL} + \newenvironment{RTL}{\beginR}{\endR} + \newenvironment{LTR}{\beginL}{\endL} +\fi +$endif$ +$for(header-includes)$ +$header-includes$ +$endfor$ + +$if(title)$ +\title{$title$$if(thanks)$\thanks{$thanks$}$endif$} +$endif$ +$if(subtitle)$ +\providecommand{\subtitle}[1]{} +\subtitle{$subtitle$} +$endif$ +$if(author)$ +\author{$for(author)$$author$$sep$ \and $endfor$} +$endif$ +\date{$date$} + +\begin{document} +$if(title)$ +\maketitle +$endif$ +$if(abstract)$ +\begin{abstract} +$abstract$ +\end{abstract} +$endif$ + +$for(include-before)$ +$include-before$ + +$endfor$ +$if(toc)$ +{ +$if(colorlinks)$ +\hypersetup{linkcolor=$if(toccolor)$$toccolor$$else$black$endif$} +$endif$ +\setcounter{tocdepth}{$toc-depth$} +\tableofcontents +} +$endif$ +$if(lot)$ +\listoftables +$endif$ +$if(lof)$ +\listoffigures +$endif$ +$body$ + +$if(natbib)$ +$if(bibliography)$ +$if(biblio-title)$ +$if(book-class)$ +\renewcommand\bibname{$biblio-title$} +$else$ +\renewcommand\refname{$biblio-title$} +$endif$ +$endif$ +\bibliography{$for(bibliography)$$bibliography$$sep$,$endfor$} + +$endif$ +$endif$ +$if(biblatex)$ +\printbibliography$if(biblio-title)$[title=$biblio-title$]$endif$ + +$endif$ +$for(include-after)$ +$include-after$ + +$endfor$ +\end{document} diff --git a/1682/gas_hale.md b/1682/gas_hale.md new file mode 100644 index 00000000..69d0ddb0 --- /dev/null +++ b/1682/gas_hale.md @@ -0,0 +1,238 @@ +# Gas HALE model +```python +#inPDF: skip + +from numpy import pi +from gpkit import VectorVariable, Variable, Model, units +from gpkit.tools import te_exp_minus1 +import gpkit +import numpy as np +gpkit.settings['latex_modelname'] = False + +class GasPoweredHALE(Model): + def setup(self): + constraints = [] +``` + + +## Flight segment definitions +```python + + # define number of segments + NSeg = 3 + #Note: NSeg has to be an odd number + # defining indices of different flight segments + NLoiter = (NSeg-1)/2 + if NSeg == 3: + NCruise = [0,2] + elif NSeg == 7: + Nclimb = [0,2,4,6] + NCruise = [1,5] +``` + + +# Fuel weight model +```python + + MTOW = Variable('MTOW', 'lbf', 'max take off weight') + W_end = VectorVariable(NSeg, 'W_{end}', 'lbf', 'segment-end weight') + W_fuel = VectorVariable(NSeg, 'W_{fuel}', 'lbf', 'segment-fuel weight') + W_zfw = Variable('W_{zfw}', 'lbf', 'Zero fuel weight') + W_pay = Variable('W_{pay}',10,'lbf', 'Payload weight') + W_avionics = Variable('W_{avionics}', 2, 'lbf', 'Avionics weight') + f_airframe = Variable('f_{airframe}', 0.25, '-', 'airframe weight fraction') + W_airframe = Variable('W_{airframe}', 'lbf', 'airframe weight') + W_begin = W_end.left # define beginning of segment weight + W_begin[0] = MTOW +``` + +## Assumptions + +* Mass take off weight is greater than the end of the first segment weight plus that segment fuel weight. +* The end of each flight segment weight must be greater than the next end of flight segment weight plus the fuel weight of the next flight segment. +* The end of the last flight segment weight must be greater than the zero fuel weight + +```python + + constraints.extend([MTOW >= W_end[0] + W_fuel[0], + W_end[:-1] >= W_end[1:] + W_fuel[1:], + W_end[-1] >= W_zfw, + W_airframe >= f_airframe*MTOW]) +``` + + +# Steady level flight model +## Assumptions +* Steady state flight +* Angle of attack zero +* Thrust equals drag +* Lift equals weight +* The weight is approximated by the average weight of the flight segment. +* The average weight can be approximated by: $W_{avg} = \sqrt{W_{begin} W_{end}}$. Where $W_{begin}$ is the beginning of the flight segment and $W_{end}$ is the end of the flight segment. + +```python + + CD = VectorVariable(NSeg, 'C_D', '-', 'Drag coefficient') + CL = VectorVariable(NSeg, 'C_L', '-', 'Lift coefficient') + V = VectorVariable(NSeg, 'V', 'm/s','cruise speed') + rho = VectorVariable(NSeg, r'\rho', 'kg/m^3', 'air density') + S = Variable('S', 16, 'ft^2', 'wing area') + eta_prop = VectorVariable(NSeg, r'\eta_{prop}', [0.8,0.6,0.8], '-', + 'propulsive efficiency') + P_shaft = VectorVariable(NSeg, 'P_{shaft}', 'hp', 'Shaft power') +``` + +# Climb model +```python + + h_dot = Variable(NSeg, 'h_{dot}', [200,0,0], 'ft/min', 'Climb rate') + constraints.extend([P_shaft >= V*(W_end+W_begin)/2*CD/CL/eta_prop + W_begin*h_dot/eta_prop, + 0.5*rho*CL*S*V**2 >= (W_end+W_begin)/2]) +``` + +# Engine Model +```python + + W_eng = Variable('W_{eng}', 'lbf', 'Engine weight') + W_engtot = Variable('W_{eng-tot}', 'lbf', 'Installed engine weight') + W_engref = Variable('W_{eng-ref}', 4.4107, 'lbf', 'Reference engine weight') + P_shaftref = Variable('P_{shaft-ref}', 2.295, 'hp', 'reference shaft power') +``` + +## Engine Weight constraints +```python + + constraints.extend([W_eng/W_engref >= 0.5538*(P_shaft/P_shaftref)**1.075, + W_engtot >= 2.572*W_eng**0.922*units('lbf')**0.078]) +``` + +# Weight breakdown +```python + + constraints.extend([W_airframe >= f_airframe*MTOW, + W_zfw >= W_pay + W_avionics + W_airframe + W_engtot]) +``` + +# Breguet Range +## Assumptions +* Constant speed during each flight section +* Constant BSFC +* The $\ln$ can be approximated using a Taylor-series expansion + +```python + + z_bre = VectorVariable(NSeg, 'z_{bre}', '-', 'breguet coefficient') + BSFC = VectorVariable(NSeg,'BSFC', [0.5,.55,0.6], 'lbf/hr/hp', 'brake specific fuel consumption') + t = VectorVariable(NSeg, 't', 'days', 'time on station') + R = Variable('R', 200, 'nautical_miles', 'range to station') + g = Variable('g', 9.81, 'm/s^2', 'Gravitational acceleration') + + constraints.extend([z_bre >= V*t*BSFC*CD/CL/eta_prop, + R == V[NCruise]*t[NCruise], + t[NLoiter] == 5*units('days'), + W_fuel/W_end >= te_exp_minus1(z_bre, 3)]) +``` + + +# Aerodynamics model +## Assumptions +* The wing is a box shape. +* The non-wing drag is a constant +* The stall factor is based off standard airfoil polar. +* Reference length for Reynolds number is teh chord. +* The skin friction is based off of Blasius flat plate. +* The form factor for the wing is constant. + +```python + + + Cd0 = Variable('C_{d0}', 0.02, '-', 'Non-wing drag coefficient') + CLmax = Variable('C_{L-max}', 1.5, '-', 'Maximum lift coefficient') + e = Variable('e', 0.9, '-', 'Spanwise efficiency') + AR = Variable('AR', '-', 'Aspect ratio') + b = Variable('b', 'ft', 'Span') + mu = Variable(r'\mu', 1.5e-5, 'N*s/m^2', 'Dynamic viscosity') + Re = VectorVariable(NSeg, 'Re', '-', 'Reynolds number') + Cf = VectorVariable(NSeg, '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*AR) + cl_16*CL**16, + b**2 == S*AR, +``` + +In place of an actual structural model, we impose $AR \leq 20$. +```python + + AR <= 20, + CL <= CLmax, + Re == rho*V/mu*(S/AR)**0.5, + Cf >= 0.074/Re**0.2]) +``` + +# Atmosphere model +## Assumptions +* Valid only to the top of the troposphere. + +## References +* [wp:Density of Air](http://en.wikipedia.org/wiki/Density_of_air#Altitude) + +```python + + + h = VectorVariable(NSeg, 'h', 'ft', 'Altitude') + gamma = Variable(r'\gamma',1.4,'-', 'Heat capacity ratio of air') + p_sl = Variable('p_{sl}', 101325, 'Pa', 'Pressure at sea level') + T_sl = VectorVariable(NSeg, 'T_{sl}', [288.15,288.15,288.15], 'K', + 'Temperature at sea level') + L_atm = Variable('L_{atm}', 0.0065, 'K/m', 'Temperature lapse rate') + T_atm = VectorVariable(NSeg, 'T_{atm}', 'K', 'Air temperature') + a_atm = VectorVariable(NSeg, 'a_{atm}','m/s', 'Speed of sound at altitude') + R_spec = Variable('R_{spec}', 287.058,'J/kg/K', 'Specific gas constant of air') + TH = (g/R_spec/L_atm).value.magnitude # dimensionless + + constraints.extend([#h <= [20000, 20000, 20000]*units.m, + T_sl >= T_atm + L_atm*h, # Temp decreases w/ altitude + rho == p_sl*T_atm**(TH-1)/R_spec/(T_sl**TH), + h[NLoiter] >= 15000*units('ft'), # makes sure that the loiter occurs above minimum h + ]) +``` + + +# Wind speed model +```python + + V_wind = VectorVariable(NSeg, 'V_{wind}', 'm/s', 'wind speed') + wd_cnst = Variable('wd_{cnst}', 0.0015, 'm/s/ft', + 'wind speed constant predicted by model') + #0.002 is worst case, 0.0015 is mean at 45d + wd_ln = Variable('wd_{ln}', 8.845, 'm/s', + 'linear wind speed variable') + #13.009 is worst case, 8.845 is mean at 45deg + h_min = Variable('h_{min}', 11800, 'ft', 'minimum height') + h_max = Variable('h_{max}', 20866, 'ft', 'maximum height') + + constraints.extend([V_wind >= wd_cnst*h + wd_ln, + V >= V_wind, + h[NCruise] >= h_min]) +``` + + +# Conclusion +```python + + objective = MTOW + return objective, constraints + +if __name__ == "__main__": + M = GasPoweredHALE() + M.solve() +``` + + +# Solution +```python +#inPDF: replace with sol.generated.tex + with open("sol.generated.tex", "w") as f: + f.write(M.solution.table(latex=True)) +```