{ "cells": [ { "cell_type": "markdown", "id": "c6b2e4d0-bf43-4a8a-a8e7-4fa081d61317", "metadata": { "extensions": { "jupyter_dashboards": { "activeView": "grid_default", "views": { "grid_default": { "col": 0, "height": 1, "hidden": false, "row": 0, "width": 1 } } } }, "tags": [] }, "source": [ "## Hot air balloon - lift calculator\n", "### Inverted pyramid shape\n", "[Source code](https://gitea.citizen4.eu/sp9unb/balloon-calc) \n", "\n", "[Run in mybinder.org IDE](https://mybinder.org/v2/git/https%3A%2F%2Fgitea.citizen4.eu%2Fsp9unb%2Fballoon-calc/HEAD?labpath=work%2Fhotair-pyramid.ipynb) " ] }, { "cell_type": "code", "execution_count": 1, "id": "6ea87a15-f571-4611-8487-5b7556e2ef45", "metadata": { "extensions": { "jupyter_dashboards": { "activeView": "grid_default", "views": { "grid_default": { "col": null, "height": 2, "hidden": true, "row": null, "width": 2 } } } } }, "outputs": [], "source": [ "# https://pythreejs.readthedocs.io\n", "from pythreejs import *\n", "from IPython.display import HTML,display\n", "from math import pi\n", "\n", "# https://ipywidgets.readthedocs.io\n", "import ipywidgets as widgets\n", "from ipywidgets import Layout\n", "\n", "# https://pypi.org/project/termcolor/\n", "from termcolor import colored\n", "\n", "#from scipy.interpolate import interp1d\n", "#import numpy as np\n", "\n", "#math\n", "from math import sin, tan, sqrt" ] }, { "cell_type": "code", "execution_count": 2, "id": "d075a994-76bb-46f7-bdfb-cc6ef449dc43", "metadata": { "extensions": { "jupyter_dashboards": { "activeView": "grid_default", "views": { "grid_default": { "col": null, "height": 2, "hidden": true, "row": null, "width": 2 } } } } }, "outputs": [], "source": [ "# air density–temperature relationship at 1 atm or 101.325 kPa\n", "# https://en.wikipedia.org/wiki/Density_of_air\n", "# https://www.engineersedge.com/calculators/air-density.htm\n", "# temp in st.C density in g/m3\n", "\n", "#temp = [-25,-20,-15,-10,-5,0,5,10,15,20,25,30,35]\n", "#dens = [1422.4,1394.3,1367.3,1341.3,1316.3,1292.2,1269.0,1246.6,1225.0,1204.1,1183.9,1164.4,1145.5]\n", "#dens_temp_func = interp1d(temp, dens)\n", "\n", "\n", "def airDensity(temp=0.0):\n", " tempK = temp + 273.0 # absolute temperature [K]\n", " p = 101325.0 # pressure [Pa]\n", " rSpec = 287.0500676 # specific gas constant for dry air [J⋅kg−1⋅K−1]\n", " return 1000.0 * p / ( rSpec * tempK )" ] }, { "cell_type": "code", "execution_count": 3, "id": "229c0a36-bf1f-4c07-884c-f3522d5eaae5", "metadata": {}, "outputs": [], "source": [ "# math: https://pl.wikipedia.org/wiki/Wielok%C4%85t_foremny\n", "\n", "# radius of the circle described on the polygon\n", "def outradius(a=1.0,n=3):\n", " return a / ( 2 * sin( pi / n ))\n", "\n", "# radius of the circle inscribed in the polygon\n", "def inradius(a=1.0,n=3):\n", " return a / ( 2 * tan( pi / n )) \n", "\n", "# edge length\n", "def edge_len(r=1.0,h=1.0):\n", " return sqrt(pow(r,2) + pow(h,2))\n", "\n", "#pyramid area/volume\n", "def base_area(a=1.0,n=3):\n", " return 0.5 * n * pow(outradius(a,n),2) * sin( 2 * pi / n)\n", "\n", "def volume(a=1.0,h1=1.0,h2=1.0,n=3):\n", " return base_area(a,n) * ( h1 + h2 ) / 3\n", " \n", "def surface_area(a=1.0,h1=1.0,h2=1.0,n=3):\n", " return 0.5 * a * n * ( sqrt( pow(h1,2) + pow(inradius(a,n),2)) + sqrt( pow(h2,2) + pow(inradius(a,n),2)) )\n", " \n" ] }, { "cell_type": "code", "execution_count": 5, "id": "2f3b63fd-d5ea-40b6-a2f9-b31c84cfef36", "metadata": { "extensions": { "jupyter_dashboards": { "activeView": "grid_default", "views": { "grid_default": { "col": null, "height": 2, "hidden": true, "row": null, "width": 2 } } } } }, "outputs": [ { "data": { "text/html": [ "" ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "e68f02b1e1c548d482d0e63bb21611dc", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(IntSlider(value=3, description='Segment num:', layout=Layout(width='500px'), max=12, min=3, sty…" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def f(num,width,heightT,heightB,airTemp,hotAirTemp,coatDens,tapeDens,payloadWeight):\n", "\n", " out=widgets.Output(layout={'margin': '10px 10px 10px 20px'}) \n", " with out: \n", " # Volume\n", " vol = volume(width,heightB,heightT,num)\n", " print( \"Volume: {:.2f} [m3]\".format(vol)) \n", " # Area\n", " area = surface_area(width,heightB,heightT,num)\n", " print( \"Area: {:.2f} [m2]\".format(area)) \n", " # Coating density (from: protective film for painting): 300g / 4x5m = 15g/m2 \n", " coatingWeight = coatDens * area\n", " print( \"Coating weight: {:.2f} [g]\".format(coatingWeight)) \n", " # adhesive tape density : average 2g/m \n", " tapeLength = num * ( edge_len(outradius(width,num),heightT) + edge_len(outradius(width,num),heightB) )\n", " tapeWeight = tapeDens * tapeLength\n", " print( \"Adh.tape length: {:.2f} [m]\".format(tapeLength)) \n", " print( \"Adh.tape weight: {:.2f} [g]\".format(tapeWeight)) \n", " # Lift per volume g/m3 \n", " # airDens = dens_temp_func( airTemp )\n", " # hotAirDens = dens_temp_func( hotAirTemp ) \n", " airDens = airDensity( airTemp )\n", " hotAirDens = airDensity( hotAirTemp ) \n", " lift = airDens - hotAirDens\n", " print( \"Lift: {:.2f} [g/m3]\".format(lift)) \n", " # Total lift force lift * volume \n", " totalLiftForce = lift * vol\n", " print( \"Total lift force: {:.2f} [g]\".format(totalLiftForce)) \n", " # Free lift force totalLiftForce - coatingWeight \n", " freeLiftForce = totalLiftForce - coatingWeight - tapeWeight - payloadWeight\n", " if freeLiftForce < 0:\n", " color = 'red'\n", " else:\n", " color = None\n", " print( \"Free lift force:\", colored(\"{:.2f} [g]\".format(freeLiftForce),color)) \n", "\n", " \n", "# coating geometry \n", " bottomGeometry = CylinderBufferGeometry(\n", " radiusTop=outradius(width,num), \n", " radiusBottom=0.0, \n", " height=heightB, \n", " radialSegments=num, \n", " heightSegments=1, \n", " openEnded=True, \n", " thetaStart=0, \n", " thetaLength=2.0*pi)\n", " \n", " bottomCylinder = Mesh(bottomGeometry,\n", " material=MeshLambertMaterial(color='#c0c0c0'),\n", " position=[0,0,0] \n", " )\n", " \n", " zTop = ( heightB + heightT ) / 2.0\n", " topGeometry = CylinderBufferGeometry(\n", " radiusTop=0.0, \n", " radiusBottom=outradius(width,num), \n", " height=heightT, \n", " radialSegments=num, \n", " heightSegments=1, \n", " openEnded=True, \n", " thetaStart=0, \n", " thetaLength=2.0*pi)\n", " \n", " topCylinder = Mesh(topGeometry,\n", " material=MeshLambertMaterial(color='#c0c0c0'),\n", " position=[0,zTop,0] \n", " ) \n", " \n", " keyLight = DirectionalLight(color='white', position=[3, 5, 1], intensity=0.5)\n", "\n", " c = PerspectiveCamera(position=[2, 2, 6], up=[0, 1, 0], children=[keyLight])\n", "\n", " scene = Scene(children=[bottomCylinder,topCylinder, c, AmbientLight(color='#777777')], background=None)\n", "\n", " renderer = Renderer(camera=c,\n", " scene=scene,\n", " alpha=True,\n", " clearOpacity=1.0,\n", " clearColor='#62a0ea',\n", " controls=[OrbitControls(controlling=c)])\n", " display(widgets.HBox([renderer, out])) \n", "\n", "\n", "\n", "display(HTML(''''''))\n", "\n", "layout=Layout(width='500px')\n", "style = {'description_width': 'initial'}\n", " \n", "num=widgets.IntSlider(min=3, max=12, step=1, value=3, description='Segment num:',layout=layout,style=style) \n", "width=widgets.FloatSlider(min=0.1, max=5.0, step=0.1, value=3.0, description='Segment width [m]:',readout_format='.1f',layout=layout,style=style) \n", "heightT=widgets.FloatSlider(min=0.1, max=5.0, step=0.1, value=1.0, description='Height top [m]:',readout_format='.1f',layout=layout,style=style) \n", "heightB=widgets.FloatSlider(min=0.1, max=5.0, step=0.1, value=2.0, description='Height bottom [m]:',readout_format='.1f',layout=layout,style=style) \n", "airTemp=widgets.FloatSlider(min=-40, max=35, step=1.0, value=10.0, description='Air temp.[°C]:',readout_format='.0f',layout=layout,style=style) \n", "hotAirTemp=widgets.FloatSlider(min=-40, max=55, step=1.0, value=35.0, description='Hot air temp.[°C]:',readout_format='.0f',layout=layout,style=style)\n", "coatDens=widgets.FloatSlider(min=1, max=50, step=1.0, value=15.0, description='Coating density [g/m2]:',readout_format='.0f',layout=layout,style=style) \n", "tapeDens=widgets.FloatSlider(min=0.5, max=10, step=0.5, value=2.0, description='Adh. tape density [g/m]:',readout_format='.1f',layout=layout,style=style)\n", "payloadWeight=widgets.FloatSlider(min=0.0, max=1000.0, step=1, value=0.0, description='Payload weight [g]:',readout_format='.0f',layout=layout,style=style)\n", " \n", "w = widgets.interactive_output(f, { 'num' : num,\n", " 'width' : width,\n", " 'heightT' : heightT,\n", " 'heightB' : heightB,\n", " 'airTemp' : airTemp,\n", " 'hotAirTemp' : hotAirTemp,\n", " 'coatDens' : coatDens,\n", " 'tapeDens' : tapeDens,\n", " 'payloadWeight' : payloadWeight\n", " }\n", " )\n", "\n", "widgets.VBox([num, width, heightT, heightB, airTemp, hotAirTemp, coatDens,tapeDens,payloadWeight, w])\n" ] }, { "cell_type": "code", "execution_count": null, "id": "0c7663e8-418e-47a9-9c2b-33d787f109ff", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "extensions": { "jupyter_dashboards": { "activeView": "grid_default", "version": 1, "views": { "grid_default": { "cellMargin": 2, "defaultCellHeight": 60, "maxColumns": 12, "name": "grid", "type": "grid" } } } }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.2" } }, "nbformat": 4, "nbformat_minor": 5 }